+++ /dev/null
-APPLE PUBLIC SOURCE LICENSE
-Version 2.0 - August 6, 2003
-
-Please read this License carefully before downloading this software.
-By downloading or using this software, you are agreeing to be bound by
-the terms of this License. If you do not or cannot agree to the terms
-of this License, please do not download or use the software.
-
-1. General; Definitions. This License applies to any program or other
-work which Apple Computer, Inc. ("Apple") makes publicly available and
-which contains a notice placed by Apple identifying such program or
-work as "Original Code" and stating that it is subject to the terms of
-this Apple Public Source License version 2.0 ("License"). As used in
-this License:
-
-1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
-the grantor of rights, (i) claims of patents that are now or hereafter
-acquired, owned by or assigned to Apple and (ii) that cover subject
-matter contained in the Original Code, but only to the extent
-necessary to use, reproduce and/or distribute the Original Code
-without infringement; and (b) in the case where You are the grantor of
-rights, (i) claims of patents that are now or hereafter acquired,
-owned by or assigned to You and (ii) that cover subject matter in Your
-Modifications, taken alone or in combination with Original Code.
-
-1.2 "Contributor" means any person or entity that creates or
-contributes to the creation of Modifications.
-
-1.3 "Covered Code" means the Original Code, Modifications, the
-combination of Original Code and any Modifications, and/or any
-respective portions thereof.
-
-1.4 "Externally Deploy" means: (a) to sublicense, distribute or
-otherwise make Covered Code available, directly or indirectly, to
-anyone other than You; and/or (b) to use Covered Code, alone or as
-part of a Larger Work, in any way to provide a service, including but
-not limited to delivery of content, through electronic communication
-with a client other than You.
-
-1.5 "Larger Work" means a work which combines Covered Code or portions
-thereof with code not governed by the terms of this License.
-
-1.6 "Modifications" mean any addition to, deletion from, and/or change
-to, the substance and/or structure of the Original Code, any previous
-Modifications, the combination of Original Code and any previous
-Modifications, and/or any respective portions thereof. When code is
-released as a series of files, a Modification is: (a) any addition to
-or deletion from the contents of a file containing Covered Code;
-and/or (b) any new file or other representation of computer program
-statements that contains any part of Covered Code.
-
-1.7 "Original Code" means (a) the Source Code of a program or other
-work as originally made available by Apple under this License,
-including the Source Code of any updates or upgrades to such programs
-or works made available by Apple under this License, and that has been
-expressly identified by Apple as such in the header file(s) of such
-work; and (b) the object code compiled from such Source Code and
-originally made available by Apple under this License.
-
-1.8 "Source Code" means the human readable form of a program or other
-work that is suitable for making modifications to it, including all
-modules it contains, plus any associated interface definition files,
-scripts used to control compilation and installation of an executable
-(object code).
-
-1.9 "You" or "Your" means an individual or a legal entity exercising
-rights under this License. For legal entities, "You" or "Your"
-includes any entity which controls, is controlled by, or is under
-common control with, You, where "control" means (a) the power, direct
-or indirect, to cause the direction or management of such entity,
-whether by contract or otherwise, or (b) ownership of fifty percent
-(50%) or more of the outstanding shares or beneficial ownership of
-such entity.
-
-2. Permitted Uses; Conditions & Restrictions. Subject to the terms
-and conditions of this License, Apple hereby grants You, effective on
-the date You accept this License and download the Original Code, a
-world-wide, royalty-free, non-exclusive license, to the extent of
-Apple's Applicable Patent Rights and copyrights covering the Original
-Code, to do the following:
-
-2.1 Unmodified Code. You may use, reproduce, display, perform,
-internally distribute within Your organization, and Externally Deploy
-verbatim, unmodified copies of the Original Code, for commercial or
-non-commercial purposes, provided that in each instance:
-
-(a) You must retain and reproduce in all copies of Original Code the
-copyright and other proprietary notices and disclaimers of Apple as
-they appear in the Original Code, and keep intact all notices in the
-Original Code that refer to this License; and
-
-(b) You must include a copy of this License with every copy of Source
-Code of Covered Code and documentation You distribute or Externally
-Deploy, and You may not offer or impose any terms on such Source Code
-that alter or restrict this License or the recipients' rights
-hereunder, except as permitted under Section 6.
-
-2.2 Modified Code. You may modify Covered Code and use, reproduce,
-display, perform, internally distribute within Your organization, and
-Externally Deploy Your Modifications and Covered Code, for commercial
-or non-commercial purposes, provided that in each instance You also
-meet all of these conditions:
-
-(a) You must satisfy all the conditions of Section 2.1 with respect to
-the Source Code of the Covered Code;
-
-(b) You must duplicate, to the extent it does not already exist, the
-notice in Exhibit A in each file of the Source Code of all Your
-Modifications, and cause the modified files to carry prominent notices
-stating that You changed the files and the date of any change; and
-
-(c) If You Externally Deploy Your Modifications, You must make
-Source Code of all Your Externally Deployed Modifications either
-available to those to whom You have Externally Deployed Your
-Modifications, or publicly available. Source Code of Your Externally
-Deployed Modifications must be released under the terms set forth in
-this License, including the license grants set forth in Section 3
-below, for as long as you Externally Deploy the Covered Code or twelve
-(12) months from the date of initial External Deployment, whichever is
-longer. You should preferably distribute the Source Code of Your
-Externally Deployed Modifications electronically (e.g. download from a
-web site).
-
-2.3 Distribution of Executable Versions. In addition, if You
-Externally Deploy Covered Code (Original Code and/or Modifications) in
-object code, executable form only, You must include a prominent
-notice, in the code itself as well as in related documentation,
-stating that Source Code of the Covered Code is available under the
-terms of this License with information on how and where to obtain such
-Source Code.
-
-2.4 Third Party Rights. You expressly acknowledge and agree that
-although Apple and each Contributor grants the licenses to their
-respective portions of the Covered Code set forth herein, no
-assurances are provided by Apple or any Contributor that the Covered
-Code does not infringe the patent or other intellectual property
-rights of any other entity. Apple and each Contributor disclaim any
-liability to You for claims brought by any other entity based on
-infringement of intellectual property rights or otherwise. As a
-condition to exercising the rights and licenses granted hereunder, You
-hereby assume sole responsibility to secure any other intellectual
-property rights needed, if any. For example, if a third party patent
-license is required to allow You to distribute the Covered Code, it is
-Your responsibility to acquire that license before distributing the
-Covered Code.
-
-3. Your Grants. In consideration of, and as a condition to, the
-licenses granted to You under this License, You hereby grant to any
-person or entity receiving or distributing Covered Code under this
-License a non-exclusive, royalty-free, perpetual, irrevocable license,
-under Your Applicable Patent Rights and other intellectual property
-rights (other than patent) owned or controlled by You, to use,
-reproduce, display, perform, modify, sublicense, distribute and
-Externally Deploy Your Modifications of the same scope and extent as
-Apple's licenses under Sections 2.1 and 2.2 above.
-
-4. Larger Works. You may create a Larger Work by combining Covered
-Code with other code not governed by the terms of this License and
-distribute the Larger Work as a single product. In each such instance,
-You must make sure the requirements of this License are fulfilled for
-the Covered Code or any portion thereof.
-
-5. Limitations on Patent License. Except as expressly stated in
-Section 2, no other patent rights, express or implied, are granted by
-Apple herein. Modifications and/or Larger Works may require additional
-patent licenses from Apple which Apple may grant in its sole
-discretion.
-
-6. Additional Terms. You may choose to offer, and to charge a fee for,
-warranty, support, indemnity or liability obligations and/or other
-rights consistent with the scope of the license granted herein
-("Additional Terms") to one or more recipients of Covered Code.
-However, You may do so only on Your own behalf and as Your sole
-responsibility, and not on behalf of Apple or any Contributor. You
-must obtain the recipient's agreement that any such Additional Terms
-are offered by You alone, and You hereby agree to indemnify, defend
-and hold Apple and every Contributor harmless for any liability
-incurred by or claims asserted against Apple or such Contributor by
-reason of any such Additional Terms.
-
-7. Versions of the License. Apple may publish revised and/or new
-versions of this License from time to time. Each version will be given
-a distinguishing version number. Once Original Code has been published
-under a particular version of this License, You may continue to use it
-under the terms of that version. You may also choose to use such
-Original Code under the terms of any subsequent version of this
-License published by Apple. No one other than Apple has the right to
-modify the terms applicable to Covered Code created under this
-License.
-
-8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
-part pre-release, untested, or not fully tested works. The Covered
-Code may contain errors that could cause failures or loss of data, and
-may be incomplete or contain inaccuracies. You expressly acknowledge
-and agree that use of the Covered Code, or any portion thereof, is at
-Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
-WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
-APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
-PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
-ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
-NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
-MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
-PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
-PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
-INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
-FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
-THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
-ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
-ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
-AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
-You acknowledge that the Covered Code is not intended for use in the
-operation of nuclear facilities, aircraft navigation, communication
-systems, or air traffic control machines in which case the failure of
-the Covered Code could lead to death, personal injury, or severe
-physical or environmental damage.
-
-9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
-EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
-SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
-TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
-ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
-TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
-APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
-REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
-INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
-TO YOU. In no event shall Apple's total liability to You for all
-damages (other than as may be required by applicable law) under this
-License exceed the amount of fifty dollars ($50.00).
-
-10. Trademarks. This License does not grant any rights to use the
-trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
-"QuickTime", "QuickTime Streaming Server" or any other trademarks,
-service marks, logos or trade names belonging to Apple (collectively
-"Apple Marks") or to any trademark, service mark, logo or trade name
-belonging to any Contributor. You agree not to use any Apple Marks in
-or as part of the name of products derived from the Original Code or
-to endorse or promote products derived from the Original Code other
-than as expressly permitted by and in strict compliance at all times
-with Apple's third party trademark usage guidelines which are posted
-at http://www.apple.com/legal/guidelinesfor3rdparties.html.
-
-11. Ownership. Subject to the licenses granted under this License,
-each Contributor retains all rights, title and interest in and to any
-Modifications made by such Contributor. Apple retains all rights,
-title and interest in and to the Original Code and any Modifications
-made by or on behalf of Apple ("Apple Modifications"), and such Apple
-Modifications will not be automatically subject to this License. Apple
-may, at its sole discretion, choose to license such Apple
-Modifications under this License, or on different terms from those
-contained in this License or may choose not to license them at all.
-
-12. Termination.
-
-12.1 Termination. This License and the rights granted hereunder will
-terminate:
-
-(a) automatically without notice from Apple if You fail to comply with
-any term(s) of this License and fail to cure such breach within 30
-days of becoming aware of such breach;
-
-(b) immediately in the event of the circumstances described in Section
-13.5(b); or
-
-(c) automatically without notice from Apple if You, at any time during
-the term of this License, commence an action for patent infringement
-against Apple; provided that Apple did not first commence
-an action for patent infringement against You in that instance.
-
-12.2 Effect of Termination. Upon termination, You agree to immediately
-stop any further use, reproduction, modification, sublicensing and
-distribution of the Covered Code. All sublicenses to the Covered Code
-which have been properly granted prior to termination shall survive
-any termination of this License. Provisions which, by their nature,
-should remain in effect beyond the termination of this License shall
-survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
-12.2 and 13. No party will be liable to any other for compensation,
-indemnity or damages of any sort solely as a result of terminating
-this License in accordance with its terms, and termination of this
-License will be without prejudice to any other right or remedy of
-any party.
-
-13. Miscellaneous.
-
-13.1 Government End Users. The Covered Code is a "commercial item" as
-defined in FAR 2.101. Government software and technical data rights in
-the Covered Code include only those rights customarily provided to the
-public as defined in this License. This customary commercial license
-in technical data and software is provided in accordance with FAR
-12.211 (Technical Data) and 12.212 (Computer Software) and, for
-Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
-Commercial Items) and 227.7202-3 (Rights in Commercial Computer
-Software or Computer Software Documentation). Accordingly, all U.S.
-Government End Users acquire Covered Code with only those rights set
-forth herein.
-
-13.2 Relationship of Parties. This License will not be construed as
-creating an agency, partnership, joint venture or any other form of
-legal association between or among You, Apple or any Contributor, and
-You will not represent to the contrary, whether expressly, by
-implication, appearance or otherwise.
-
-13.3 Independent Development. Nothing in this License will impair
-Apple's right to acquire, license, develop, have others develop for
-it, market and/or distribute technology or products that perform the
-same or similar functions as, or otherwise compete with,
-Modifications, Larger Works, technology or products that You may
-develop, produce, market or distribute.
-
-13.4 Waiver; Construction. Failure by Apple or any Contributor to
-enforce any provision of this License will not be deemed a waiver of
-future enforcement of that or any other provision. Any law or
-regulation which provides that the language of a contract shall be
-construed against the drafter will not apply to this License.
-
-13.5 Severability. (a) If for any reason a court of competent
-jurisdiction finds any provision of this License, or portion thereof,
-to be unenforceable, that provision of the License will be enforced to
-the maximum extent permissible so as to effect the economic benefits
-and intent of the parties, and the remainder of this License will
-continue in full force and effect. (b) Notwithstanding the foregoing,
-if applicable law prohibits or restricts You from fully and/or
-specifically complying with Sections 2 and/or 3 or prevents the
-enforceability of either of those Sections, this License will
-immediately terminate and You must immediately discontinue any use of
-the Covered Code and destroy all copies of it that are in your
-possession or control.
-
-13.6 Dispute Resolution. Any litigation or other dispute resolution
-between You and Apple relating to this License shall take place in the
-Northern District of California, and You and Apple hereby consent to
-the personal jurisdiction of, and venue in, the state and federal
-courts within that District with respect to this License. The
-application of the United Nations Convention on Contracts for the
-International Sale of Goods is expressly excluded.
-
-13.7 Entire Agreement; Governing Law. This License constitutes the
-entire agreement between the parties with respect to the subject
-matter hereof. This License shall be governed by the laws of the
-United States and the State of California, except that body of
-California law concerning conflicts of law.
-
-Where You are located in the province of Quebec, Canada, the following
-clause applies: The parties hereby confirm that they have requested
-that this License and all related documents be drafted in English. Les
-parties ont exige que le present contrat et tous les documents
-connexes soient rediges en anglais.
-
-EXHIBIT A.
-
-"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
-Reserved.
-
-This file contains Original Code and/or Modifications of Original Code
-as defined in and that are subject to the Apple Public Source License
-Version 2.0 (the 'License'). You may not use this file except in
-compliance with the License. Please obtain a copy of the License at
-http://www.opensource.apple.com/apsl/ and read it before using this
-file.
-
-The Original Code and all software distributed under the License are
-distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-Please see the License for the specific language governing rights and
-limitations under the License."
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: BonjourExample.cpp,v $
+Revision 1.2 2006/08/14 23:23:57 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2005/05/20 22:01:01 bradley
Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: stdafx.cpp,v $
+Revision 1.2 2006/08/14 23:23:57 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2005/05/20 22:01:02 bradley
Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: stdafx.h,v $
+Revision 1.2 2006/08/14 23:23:57 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2005/05/20 22:01:02 bradley
Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
BEGIN\r
BLOCK "040904b0"\r
BEGIN\r
- VALUE "CompanyName", "Apple Computer, Inc."\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
VALUE "FileDescription", "Bonjour Console Utility"\r
VALUE "FileVersion", MASTER_PROD_VERS_STR\r
VALUE "InternalName", "dns-sd.exe"\r
+++ /dev/null
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 39;
- objects = {
- 014CEA490018CE3211CA2923 = {
- buildRules = (
- );
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- DEBUGGING_SYMBOLS = YES;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- OPTIMIZATION_CFLAGS = "-O0";
- ZERO_LINK = NO;
- };
- isa = PBXBuildStyle;
- name = Development;
- };
- 014CEA4A0018CE3211CA2923 = {
- buildRules = (
- );
- buildSettings = {
- COPY_PHASE_STRIP = YES;
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
- ZERO_LINK = NO;
- };
- isa = PBXBuildStyle;
- name = Deployment;
- };
-//010
-//011
-//012
-//013
-//014
-//080
-//081
-//082
-//083
-//084
- 08FB7793FE84155DC02AAC07 = {
- buildSettings = {
- };
- buildStyles = (
- 014CEA490018CE3211CA2923,
- 014CEA4A0018CE3211CA2923,
- );
- hasScannedForEncodings = 1;
- isa = PBXProject;
- mainGroup = 08FB7794FE84155DC02AAC07;
- projectDirPath = "";
- targets = (
- FFF520490671177900DA3D49,
- 8DD76F740486A8DE00D96B5E,
- FF1B691006711383002304DD,
- FF1E351206711B5C003DD5BC,
- );
- };
- 08FB7794FE84155DC02AAC07 = {
- children = (
- 08FB7795FE84155DC02AAC07,
- 08FB779DFE84155DC02AAC07,
- 19C28FBDFE9D53C911CA2CBB,
- );
- isa = PBXGroup;
- name = mDNS;
- refType = 4;
- sourceTree = "<group>";
- };
- 08FB7795FE84155DC02AAC07 = {
- children = (
- 08FB7796FE84155DC02AAC07,
- FF1B6914067114AF002304DD,
- FF964DAB067115710099215A,
- FF1E351B06711BCF003DD5BC,
- FF1E352506711BD6003DD5BC,
- );
- isa = PBXGroup;
- name = Source;
- refType = 4;
- sourceTree = "<group>";
- };
- 08FB7796FE84155DC02AAC07 = {
- fileEncoding = 4;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.c;
- path = "dns-sd.c";
- refType = 4;
- sourceTree = "<group>";
- };
- 08FB779DFE84155DC02AAC07 = {
- children = (
- FF964CA90671155C0099215A,
- FF964AA00671153B0099215A,
- );
- isa = PBXGroup;
- name = Frameworks;
- refType = 4;
- sourceTree = "<group>";
- };
-//080
-//081
-//082
-//083
-//084
-//190
-//191
-//192
-//193
-//194
- 19C28FBDFE9D53C911CA2CBB = {
- children = (
- 8DD76F7E0486A8DE00D96B5E,
- FF1B691106711383002304DD,
- FF1E351306711B5C003DD5BC,
- );
- isa = PBXGroup;
- name = Products;
- refType = 4;
- sourceTree = "<group>";
- };
-//190
-//191
-//192
-//193
-//194
-//8D0
-//8D1
-//8D2
-//8D3
-//8D4
- 8DD76F740486A8DE00D96B5E = {
- buildPhases = (
- 8DD76F750486A8DE00D96B5E,
- 8DD76F760486A8DE00D96B5E,
- 8DD76F780486A8DE00D96B5E,
- 8DD76F7A0486A8DE00D96B5E,
- 8DD76F7B0486A8DE00D96B5E,
- );
- buildRules = (
- );
- buildSettings = {
- FRAMEWORK_SEARCH_PATHS = "";
- GCC_ENABLE_TRIGRAPHS = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
- GCC_PRECOMPILE_PREFIX_HEADER = NO;
- GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
- GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
- GCC_WARN_UNKNOWN_PRAGMAS = NO;
- HEADER_SEARCH_PATHS = ../mDNSShared;
- INSTALL_PATH = "$(HOME)/bin";
- LIBRARY_SEARCH_PATHS = "";
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = "dns-sd";
- REZ_EXECUTABLE = YES;
- SECTORDER_FLAGS = "";
- WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
- ZERO_LINK = NO;
- };
- dependencies = (
- );
- isa = PBXNativeTarget;
- name = "dns-sd";
- productInstallPath = "$(HOME)/bin";
- productName = mDNS;
- productReference = 8DD76F7E0486A8DE00D96B5E;
- productType = "com.apple.product-type.tool";
- };
- 8DD76F750486A8DE00D96B5E = {
- buildActionMask = 2147483647;
- files = (
- );
- isa = PBXHeadersBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- 8DD76F760486A8DE00D96B5E = {
- buildActionMask = 2147483647;
- files = (
- 8DD76F770486A8DE00D96B5E,
- );
- isa = PBXSourcesBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- 8DD76F770486A8DE00D96B5E = {
- fileRef = 08FB7796FE84155DC02AAC07;
- isa = PBXBuildFile;
- settings = {
- ATTRIBUTES = (
- );
- };
- };
- 8DD76F780486A8DE00D96B5E = {
- buildActionMask = 2147483647;
- files = (
- );
- isa = PBXFrameworksBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- 8DD76F7A0486A8DE00D96B5E = {
- buildActionMask = 2147483647;
- files = (
- );
- isa = PBXRezBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- 8DD76F7B0486A8DE00D96B5E = {
- buildActionMask = 8;
- dstPath = /usr/share/man/man1/;
- dstSubfolderSpec = 0;
- files = (
- );
- isa = PBXCopyFilesBuildPhase;
- runOnlyForDeploymentPostprocessing = 1;
- };
- 8DD76F7E0486A8DE00D96B5E = {
- explicitFileType = "compiled.mach-o.executable";
- includeInIndex = 0;
- isa = PBXFileReference;
- path = "dns-sd";
- refType = 3;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
-//8D0
-//8D1
-//8D2
-//8D3
-//8D4
-//FF0
-//FF1
-//FF2
-//FF3
-//FF4
- FF1B690C06711383002304DD = {
- buildActionMask = 2147483647;
- files = (
- );
- isa = PBXHeadersBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- FF1B690D06711383002304DD = {
- buildActionMask = 2147483647;
- files = (
- FF964DAC067115710099215A,
- );
- isa = PBXResourcesBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- FF1B690E06711383002304DD = {
- buildActionMask = 2147483647;
- files = (
- FF1B6915067114AF002304DD,
- );
- isa = PBXSourcesBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- FF1B690F06711383002304DD = {
- buildActionMask = 2147483647;
- files = (
- FF964AA10671153B0099215A,
- FF964CAA0671155C0099215A,
- );
- isa = PBXFrameworksBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- FF1B691006711383002304DD = {
- buildPhases = (
- FF1B690C06711383002304DD,
- FF1B690D06711383002304DD,
- FF1B690E06711383002304DD,
- FF1B690F06711383002304DD,
- );
- buildRules = (
- );
- buildSettings = {
- GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
- GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
- GCC_WARN_UNKNOWN_PRAGMAS = NO;
- HEADER_SEARCH_PATHS = ../mDNSShared;
- INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
- INSTALL_PATH = "$(USER_APPS_DIR)";
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "-framework Foundation -framework AppKit";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = "DNS Service Browser";
- SECTORDER_FLAGS = "";
- WARNING_CFLAGS = "-Wmost";
- };
- dependencies = (
- );
- isa = PBXNativeTarget;
- name = "DNS Service Browser";
- productName = "DNS Service Browser";
- productReference = FF1B691106711383002304DD;
- productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
-<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
-<plist version=\"1.0\">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleExecutable</key>
- <string>DNS Service Browser</string>
- <key>CFBundleGetInfoString</key>
- <string></string>
- <key>CFBundleIconFile</key>
- <string></string>
- <key>CFBundleIdentifier</key>
- <string>com.apple.DNS_Service_Browser</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string></string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1.0.0d1</string>
- <key>NSMainNibFile</key>
- <string>DNSServiceBrowser</string>
- <key>NSPrincipalClass</key>
- <string>NSApplication</string>
-</dict>
-</plist>
-";
- productType = "com.apple.product-type.application";
- };
- FF1B691106711383002304DD = {
- explicitFileType = wrapper.application;
- includeInIndex = 0;
- isa = PBXFileReference;
- path = "DNS Service Browser.app";
- refType = 3;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- FF1B6914067114AF002304DD = {
- fileEncoding = 4;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.objc;
- path = DNSServiceBrowser.m;
- refType = 4;
- sourceTree = "<group>";
- };
- FF1B6915067114AF002304DD = {
- fileRef = FF1B6914067114AF002304DD;
- isa = PBXBuildFile;
- settings = {
- };
- };
- FF1E350E06711B5C003DD5BC = {
- buildActionMask = 2147483647;
- files = (
- );
- isa = PBXHeadersBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- FF1E350F06711B5C003DD5BC = {
- buildActionMask = 2147483647;
- files = (
- FF1E352606711BD6003DD5BC,
- );
- isa = PBXResourcesBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- FF1E351006711B5C003DD5BC = {
- buildActionMask = 2147483647;
- files = (
- FF1E351C06711BCF003DD5BC,
- );
- isa = PBXSourcesBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- FF1E351106711B5C003DD5BC = {
- buildActionMask = 2147483647;
- files = (
- );
- isa = PBXFrameworksBuildPhase;
- runOnlyForDeploymentPostprocessing = 0;
- };
- FF1E351206711B5C003DD5BC = {
- buildPhases = (
- FF1E350E06711B5C003DD5BC,
- FF1E350F06711B5C003DD5BC,
- FF1E351006711B5C003DD5BC,
- FF1E351106711B5C003DD5BC,
- );
- buildRules = (
- );
- buildSettings = {
- GCC_PRECOMPILE_PREFIX_HEADER = YES;
- GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
- GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
- GCC_WARN_UNKNOWN_PRAGMAS = NO;
- HEADER_SEARCH_PATHS = ../mDNSShared;
- INFOPLIST_FILE = "DNSServiceReg-Info.plist";
- INSTALL_PATH = "$(USER_APPS_DIR)";
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "-framework Foundation -framework AppKit";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = "DNS Service Registration";
- SECTORDER_FLAGS = "";
- WARNING_CFLAGS = "-Wmost";
- };
- dependencies = (
- );
- isa = PBXNativeTarget;
- name = "DNS Service Registration";
- productName = "DNS Service Registration";
- productReference = FF1E351306711B5C003DD5BC;
- productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
-<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
-<plist version=\"1.0\">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>English</string>
- <key>CFBundleExecutable</key>
- <string>DNS Service Registration</string>
- <key>CFBundleGetInfoString</key>
- <string></string>
- <key>CFBundleIconFile</key>
- <string></string>
- <key>CFBundleIdentifier</key>
- <string>com.apple.DNS_Service_Registration</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string></string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1.0.0d1</string>
- <key>NSMainNibFile</key>
- <string>DNSServiceReg</string>
- <key>NSPrincipalClass</key>
- <string>NSApplication</string>
-</dict>
-</plist>
-";
- productType = "com.apple.product-type.application";
- };
- FF1E351306711B5C003DD5BC = {
- explicitFileType = wrapper.application;
- includeInIndex = 0;
- isa = PBXFileReference;
- path = "DNS Service Registration.app";
- refType = 3;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- FF1E351706711B6A003DD5BC = {
- containerPortal = 08FB7793FE84155DC02AAC07;
- isa = PBXContainerItemProxy;
- proxyType = 1;
- remoteGlobalIDString = FF1E351206711B5C003DD5BC;
- remoteInfo = DNSServiceReg;
- };
- FF1E351806711B6A003DD5BC = {
- isa = PBXTargetDependency;
- target = FF1E351206711B5C003DD5BC;
- targetProxy = FF1E351706711B6A003DD5BC;
- };
- FF1E351B06711BCF003DD5BC = {
- fileEncoding = 4;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.objc;
- path = DNSServiceReg.m;
- refType = 4;
- sourceTree = "<group>";
- };
- FF1E351C06711BCF003DD5BC = {
- fileRef = FF1E351B06711BCF003DD5BC;
- isa = PBXBuildFile;
- settings = {
- };
- };
- FF1E352506711BD6003DD5BC = {
- isa = PBXFileReference;
- lastKnownFileType = wrapper.nib;
- path = DNSServiceReg.nib;
- refType = 4;
- sourceTree = "<group>";
- };
- FF1E352606711BD6003DD5BC = {
- fileRef = FF1E352506711BD6003DD5BC;
- isa = PBXBuildFile;
- settings = {
- };
- };
- FF383825067117F300FEF615 = {
- containerPortal = 08FB7793FE84155DC02AAC07;
- isa = PBXContainerItemProxy;
- proxyType = 1;
- remoteGlobalIDString = 8DD76F740486A8DE00D96B5E;
- remoteInfo = "dns-sd";
- };
- FF383826067117F300FEF615 = {
- isa = PBXTargetDependency;
- target = 8DD76F740486A8DE00D96B5E;
- targetProxy = FF383825067117F300FEF615;
- };
- FF383827067117F600FEF615 = {
- containerPortal = 08FB7793FE84155DC02AAC07;
- isa = PBXContainerItemProxy;
- proxyType = 1;
- remoteGlobalIDString = FF1B691006711383002304DD;
- remoteInfo = "DNS Service Browser";
- };
- FF383828067117F600FEF615 = {
- isa = PBXTargetDependency;
- target = FF1B691006711383002304DD;
- targetProxy = FF383827067117F600FEF615;
- };
- FF964AA00671153B0099215A = {
- isa = PBXFileReference;
- lastKnownFileType = wrapper.framework;
- name = Foundation.framework;
- path = /System/Library/Frameworks/Foundation.framework;
- refType = 0;
- sourceTree = "<absolute>";
- };
- FF964AA10671153B0099215A = {
- fileRef = FF964AA00671153B0099215A;
- isa = PBXBuildFile;
- settings = {
- };
- };
- FF964CA90671155C0099215A = {
- isa = PBXFileReference;
- lastKnownFileType = wrapper.framework;
- name = AppKit.framework;
- path = /System/Library/Frameworks/AppKit.framework;
- refType = 0;
- sourceTree = "<absolute>";
- };
- FF964CAA0671155C0099215A = {
- fileRef = FF964CA90671155C0099215A;
- isa = PBXBuildFile;
- settings = {
- };
- };
- FF964DAB067115710099215A = {
- isa = PBXFileReference;
- lastKnownFileType = wrapper.nib;
- path = DNSServiceBrowser.nib;
- refType = 4;
- sourceTree = "<group>";
- };
- FF964DAC067115710099215A = {
- fileRef = FF964DAB067115710099215A;
- isa = PBXBuildFile;
- settings = {
- };
- };
- FFF520490671177900DA3D49 = {
- buildPhases = (
- );
- buildSettings = {
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = "Build All";
- SECTORDER_FLAGS = "";
- WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
- };
- dependencies = (
- FF383826067117F300FEF615,
- FF383828067117F600FEF615,
- FF1E351806711B6A003DD5BC,
- );
- isa = PBXAggregateTarget;
- name = "Build All";
- productName = "Build All";
- };
- };
- rootObject = 08FB7793FE84155DC02AAC07;
-}
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FFF520490671177900DA3D49 /* Build All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 21D91E890B12A03D003981D9 /* Build configuration list for PBXAggregateTarget "Build All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FF383826067117F300FEF615 /* PBXTargetDependency */,
+ FF383828067117F600FEF615 /* PBXTargetDependency */,
+ FF1E351806711B6A003DD5BC /* PBXTargetDependency */,
+ );
+ name = "Build All";
+ productName = "Build All";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 8DD76F770486A8DE00D96B5E /* dns-sd.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* dns-sd.c */; settings = {ATTRIBUTES = (); }; };
+ FF1B6915067114AF002304DD /* DNSServiceBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = FF1B6914067114AF002304DD /* DNSServiceBrowser.m */; };
+ FF1E351C06711BCF003DD5BC /* DNSServiceReg.m in Sources */ = {isa = PBXBuildFile; fileRef = FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */; };
+ FF1E352606711BD6003DD5BC /* DNSServiceReg.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */; };
+ FF964AA10671153B0099215A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF964AA00671153B0099215A /* Foundation.framework */; };
+ FF964CAA0671155C0099215A /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF964CA90671155C0099215A /* AppKit.framework */; };
+ FF964DAC067115710099215A /* DNSServiceBrowser.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF964DAB067115710099215A /* DNSServiceBrowser.nib */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ FF1E351706711B6A003DD5BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FF1E351206711B5C003DD5BC;
+ remoteInfo = DNSServiceReg;
+ };
+ FF383825067117F300FEF615 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8DD76F740486A8DE00D96B5E;
+ remoteInfo = "dns-sd";
+ };
+ FF383827067117F600FEF615 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FF1B691006711383002304DD;
+ remoteInfo = "DNS Service Browser";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 8DD76F7B0486A8DE00D96B5E /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 08FB7796FE84155DC02AAC07 /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dns-sd.c"; sourceTree = "<group>"; };
+ 8DD76F7E0486A8DE00D96B5E /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
+ FF1B691106711383002304DD /* DNS Service Browser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DNS Service Browser.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ FF1B6914067114AF002304DD /* DNSServiceBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceBrowser.m; sourceTree = "<group>"; };
+ FF1E351306711B5C003DD5BC /* DNS Service Registration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DNS Service Registration.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceReg.m; sourceTree = "<group>"; };
+ FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = DNSServiceReg.nib; sourceTree = "<group>"; };
+ FF964AA00671153B0099215A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ FF964CA90671155C0099215A /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+ FF964DAB067115710099215A /* DNSServiceBrowser.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = DNSServiceBrowser.nib; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8DD76F780486A8DE00D96B5E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1B690F06711383002304DD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FF964AA10671153B0099215A /* Foundation.framework in Frameworks */,
+ FF964CAA0671155C0099215A /* AppKit.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1E351106711B5C003DD5BC /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* mDNS */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB7795FE84155DC02AAC07 /* Source */,
+ 21D91EBD0B12A2B6003981D9 /* Resources */,
+ 08FB779DFE84155DC02AAC07 /* Frameworks */,
+ 19C28FBDFE9D53C911CA2CBB /* Products */,
+ );
+ name = mDNS;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB7796FE84155DC02AAC07 /* dns-sd.c */,
+ FF1B6914067114AF002304DD /* DNSServiceBrowser.m */,
+ FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 08FB779DFE84155DC02AAC07 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ FF964CA90671155C0099215A /* AppKit.framework */,
+ FF964AA00671153B0099215A /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 19C28FBDFE9D53C911CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8DD76F7E0486A8DE00D96B5E /* dns-sd */,
+ FF1B691106711383002304DD /* DNS Service Browser.app */,
+ FF1E351306711B5C003DD5BC /* DNS Service Registration.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 21D91EBD0B12A2B6003981D9 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ FF964DAB067115710099215A /* DNSServiceBrowser.nib */,
+ FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8DD76F750486A8DE00D96B5E /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1B690C06711383002304DD /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1E350E06711B5C003DD5BC /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 8DD76F740486A8DE00D96B5E /* dns-sd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 21D91E7D0B12A03D003981D9 /* Build configuration list for PBXNativeTarget "dns-sd" */;
+ buildPhases = (
+ 8DD76F750486A8DE00D96B5E /* Headers */,
+ 8DD76F760486A8DE00D96B5E /* Sources */,
+ 8DD76F780486A8DE00D96B5E /* Frameworks */,
+ 8DD76F7A0486A8DE00D96B5E /* Rez */,
+ 8DD76F7B0486A8DE00D96B5E /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "dns-sd";
+ productInstallPath = "$(HOME)/bin";
+ productName = mDNS;
+ productReference = 8DD76F7E0486A8DE00D96B5E /* dns-sd */;
+ productType = "com.apple.product-type.tool";
+ };
+ FF1B691006711383002304DD /* DNS Service Browser */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 21D91E810B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Browser" */;
+ buildPhases = (
+ FF1B690C06711383002304DD /* Headers */,
+ FF1B690D06711383002304DD /* Resources */,
+ FF1B690E06711383002304DD /* Sources */,
+ FF1B690F06711383002304DD /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "DNS Service Browser";
+ productName = "DNS Service Browser";
+ productReference = FF1B691106711383002304DD /* DNS Service Browser.app */;
+ productType = "com.apple.product-type.application";
+ };
+ FF1E351206711B5C003DD5BC /* DNS Service Registration */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 21D91E850B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Registration" */;
+ buildPhases = (
+ FF1E350E06711B5C003DD5BC /* Headers */,
+ FF1E350F06711B5C003DD5BC /* Resources */,
+ FF1E351006711B5C003DD5BC /* Sources */,
+ FF1E351106711B5C003DD5BC /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "DNS Service Registration";
+ productName = "DNS Service Registration";
+ productReference = FF1E351306711B5C003DD5BC /* DNS Service Registration.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 21D91E8D0B12A03D003981D9 /* Build configuration list for PBXProject "DNS-SD" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* mDNS */;
+ projectDirPath = "";
+ targets = (
+ FFF520490671177900DA3D49 /* Build All */,
+ 8DD76F740486A8DE00D96B5E /* dns-sd */,
+ FF1B691006711383002304DD /* DNS Service Browser */,
+ FF1E351206711B5C003DD5BC /* DNS Service Registration */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ FF1B690D06711383002304DD /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FF964DAC067115710099215A /* DNSServiceBrowser.nib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1E350F06711B5C003DD5BC /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FF1E352606711BD6003DD5BC /* DNSServiceReg.nib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ 8DD76F7A0486A8DE00D96B5E /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8DD76F760486A8DE00D96B5E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8DD76F770486A8DE00D96B5E /* dns-sd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1B690E06711383002304DD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FF1B6915067114AF002304DD /* DNSServiceBrowser.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1E351006711B5C003DD5BC /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FF1E351C06711BCF003DD5BC /* DNSServiceReg.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ FF1E351806711B6A003DD5BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FF1E351206711B5C003DD5BC /* DNS Service Registration */;
+ targetProxy = FF1E351706711B6A003DD5BC /* PBXContainerItemProxy */;
+ };
+ FF383826067117F300FEF615 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8DD76F740486A8DE00D96B5E /* dns-sd */;
+ targetProxy = FF383825067117F300FEF615 /* PBXContainerItemProxy */;
+ };
+ FF383828067117F600FEF615 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FF1B691006711383002304DD /* DNS Service Browser */;
+ targetProxy = FF383827067117F600FEF615 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 21D91E7E0B12A03D003981D9 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUGGING_SYMBOLS = YES;
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_ENABLE_TRIGRAPHS = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INSTALL_PATH = "$(HOME)/bin";
+ LIBRARY_SEARCH_PATHS = "";
+ OPTIMIZATION_CFLAGS = "-O0";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "dns-sd";
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ ZERO_LINK = NO;
+ };
+ name = Development;
+ };
+ 21D91E7F0B12A03D003981D9 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_ENABLE_TRIGRAPHS = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INSTALL_PATH = "$(HOME)/bin";
+ LIBRARY_SEARCH_PATHS = "";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "dns-sd";
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ ZERO_LINK = NO;
+ };
+ name = Deployment;
+ };
+ 21D91E800B12A03D003981D9 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_ENABLE_TRIGRAPHS = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INSTALL_PATH = "$(HOME)/bin";
+ LIBRARY_SEARCH_PATHS = "";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "dns-sd";
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ ZERO_LINK = NO;
+ };
+ name = Default;
+ };
+ 21D91E820B12A03D003981D9 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUGGING_SYMBOLS = YES;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
+ INSTALL_PATH = "$(USER_APPS_DIR)";
+ OPTIMIZATION_CFLAGS = "-O0";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "DNS Service Browser";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ ZERO_LINK = NO;
+ };
+ name = Development;
+ };
+ 21D91E830B12A03D003981D9 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
+ INSTALL_PATH = "$(USER_APPS_DIR)";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "DNS Service Browser";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ ZERO_LINK = NO;
+ };
+ name = Deployment;
+ };
+ 21D91E840B12A03D003981D9 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INFOPLIST_FILE = "DNSServiceBrowser-Info.plist";
+ INSTALL_PATH = "$(USER_APPS_DIR)";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "DNS Service Browser";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ };
+ name = Default;
+ };
+ 21D91E860B12A03D003981D9 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUGGING_SYMBOLS = YES;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INFOPLIST_FILE = "DNSServiceReg-Info.plist";
+ INSTALL_PATH = "$(USER_APPS_DIR)";
+ OPTIMIZATION_CFLAGS = "-O0";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "DNS Service Registration";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ ZERO_LINK = NO;
+ };
+ name = Development;
+ };
+ 21D91E870B12A03D003981D9 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INFOPLIST_FILE = "DNSServiceReg-Info.plist";
+ INSTALL_PATH = "$(USER_APPS_DIR)";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "DNS Service Registration";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ ZERO_LINK = NO;
+ };
+ name = Deployment;
+ };
+ 21D91E880B12A03D003981D9 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h";
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INFOPLIST_FILE = "DNSServiceReg-Info.plist";
+ INSTALL_PATH = "$(USER_APPS_DIR)";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = (
+ "-framework",
+ Foundation,
+ "-framework",
+ AppKit,
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "DNS Service Registration";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ };
+ name = Default;
+ };
+ 21D91E8A0B12A03D003981D9 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DEBUGGING_SYMBOLS = YES;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ OPTIMIZATION_CFLAGS = "-O0";
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "Build All";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ ZERO_LINK = NO;
+ };
+ name = Development;
+ };
+ 21D91E8B0B12A03D003981D9 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "Build All";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ ZERO_LINK = NO;
+ };
+ name = Deployment;
+ };
+ 21D91E8C0B12A03D003981D9 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "Build All";
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = (
+ "-Wmost",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ };
+ name = Default;
+ };
+ 21D91E8E0B12A03D003981D9 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Development;
+ };
+ 21D91E8F0B12A03D003981D9 /* Deployment */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Deployment;
+ };
+ 21D91E900B12A03D003981D9 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Default;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 21D91E7D0B12A03D003981D9 /* Build configuration list for PBXNativeTarget "dns-sd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 21D91E7E0B12A03D003981D9 /* Development */,
+ 21D91E7F0B12A03D003981D9 /* Deployment */,
+ 21D91E800B12A03D003981D9 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 21D91E810B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Browser" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 21D91E820B12A03D003981D9 /* Development */,
+ 21D91E830B12A03D003981D9 /* Deployment */,
+ 21D91E840B12A03D003981D9 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 21D91E850B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Registration" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 21D91E860B12A03D003981D9 /* Development */,
+ 21D91E870B12A03D003981D9 /* Deployment */,
+ 21D91E880B12A03D003981D9 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 21D91E890B12A03D003981D9 /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 21D91E8A0B12A03D003981D9 /* Development */,
+ 21D91E8B0B12A03D003981D9 /* Deployment */,
+ 21D91E8C0B12A03D003981D9 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 21D91E8D0B12A03D003981D9 /* Build configuration list for PBXProject "DNS-SD" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 21D91E8E0B12A03D003981D9 /* Development */,
+ 21D91E8F0B12A03D003981D9 /* Deployment */,
+ 21D91E900B12A03D003981D9 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
- <string>com.apple.DNS_Service_Browser</string>
+ <string>com.apple.DNSServiceBrowser</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>1.0.0d1</string>
+ <string>1.0</string>
<key>NSMainNibFile</key>
<string>DNSServiceBrowser</string>
<key>NSPrincipalClass</key>
-/*\r
+/* -*- Mode: C; tab-width: 4 -*-\r
+ *\r
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.\r
*\r
- * @APPLE_LICENSE_HEADER_START@\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
* \r
- * This file contains Original Code and/or Modifications of Original Code\r
- * as defined in and that are subject to the Apple Public Source License\r
- * Version 2.0 (the 'License'). You may not use this file except in\r
- * compliance with the License. Please obtain a copy of the License at\r
- * http://www.opensource.apple.com/apsl/ and read it before using this\r
- * file.\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
* \r
- * The Original Code and all software distributed under the License are\r
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\r
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\r
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\r
- * Please see the License for the specific language governing rights and\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
* limitations under the License.\r
- * \r
- * @APPLE_LICENSE_HEADER_END@\r
\r
Change History (most recent first):\r
\r
$Log: AssemblyInfo.cs,v $
+Revision 1.2 2006/08/14 23:23:58 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/07/19 07:54:24 shersche
Initial revision
\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSServiceBrowser.cs,v $
+Revision 1.7 2006/08/14 23:23:58 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.6 2005/02/10 22:35:06 cheshire
<rdar://problem/3727944> Update name
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSServiceBrowser.m,v $
+Revision 1.35 2006/11/27 08:27:49 mkrochma
+Fix a crashing bug
+
+Revision 1.34 2006/11/24 05:41:07 mkrochma
+More cleanup and more service types
+
+Revision 1.33 2006/11/24 01:34:24 mkrochma
+Display interface index and query for IPv6 addresses even when there's no IPv4
+
+Revision 1.32 2006/11/24 00:25:31 mkrochma
+<rdar://problem/4084652> Tools: DNS Service Browser contains some bugs
+
+Revision 1.31 2006/08/14 23:23:55 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.30 2005/01/27 17:46:16 cheshire
Added comment
Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
Revision 1.27 2003/11/19 18:49:48 rpantos
-<rdar://problem/3282283>: couple of little tweaks to previous checkin
+<rdar://problem/3282283> couple of little tweaks to previous checkin
Revision 1.26 2003/11/07 19:35:20 rpantos
-<rdar://problem/3282283>/6: Display multiple IP addresses. Connect using host rather than IP addr.
+<rdar://problem/3282283> Display multiple IP addresses. Connect using host rather than IP addr.
Revision 1.25 2003/10/29 05:16:54 rpantos
Checkpoint: transition from DNSServiceDiscovery.h to dns_sd.h
Revision 1.24 2003/10/28 02:25:45 rpantos
-<rdar://problem/3282283>/9,10: Cancel pending resolve when focus changes or service disappears.
+<rdar://problem/3282283> Cancel pending resolve when focus changes or service disappears.
Revision 1.23 2003/10/28 01:29:15 rpantos
-<rdar://problem/3282283>/4,5: Restructure a bit to make arrow keys work & views behave better.
+<rdar://problem/3282283> Restructure a bit to make arrow keys work & views behave better.
Revision 1.22 2003/10/28 01:23:27 rpantos
-<rdar://problem/3282283>/11: Bail if mDNS cannot be initialized at startup.
+<rdar://problem/3282283> Bail if mDNS cannot be initialized at startup.
Revision 1.21 2003/10/28 01:19:45 rpantos
-<rdar://problem/3282283>/3,11: Do not put a trailing '.' on service names. Handle PATH for HTTP txtRecords.
+<rdar://problem/3282283> Do not put a trailing '.' on service names. Handle PATH for HTTP txtRecords.
Revision 1.20 2003/10/28 01:13:49 rpantos
-<rdar://problem/3282283>/2: Remove filter when displaying browse results.
+<rdar://problem/3282283> Remove filter when displaying browse results.
Revision 1.19 2003/10/28 01:10:14 rpantos
-<rdar://problem/3282283>/1: Change 'compare' to 'caseInsensitiveCompare' to fix sort order.
+<rdar://problem/3282283> Change 'compare' to 'caseInsensitiveCompare' to fix sort order.
Revision 1.18 2003/08/12 19:55:07 cheshire
Update to APSL 2.0
- */
+*/
+#import <Cocoa/Cocoa.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
#include <arpa/inet.h>
#include <netdb.h>
-#include <nameser.h>
#include <sys/select.h>
-
-#import <Cocoa/Cocoa.h>
-#import <DNSServiceDiscovery/DNSServiceDiscovery.h>
-
#include <netinet/in.h>
-#include "dns_sd.h"
+#include <unistd.h>
+#include <dns_sd.h>
-@class ServiceController; // holds state corresponding to outstanding DNSServiceRef
+@class ServiceController; // holds state corresponding to outstanding DNSServiceRef
@interface BrowserController : NSObject
{
- IBOutlet id domainField;
IBOutlet id nameField;
IBOutlet id typeField;
IBOutlet id ipAddressField;
IBOutlet id ip6AddressField;
IBOutlet id portField;
+ IBOutlet id interfaceField;
IBOutlet id textField;
- NSMutableArray *srvtypeKeys;
- NSMutableArray *srvnameKeys;
- NSMutableArray *domainKeys;
- NSMutableArray *nameKeys;
- NSString *Domain;
- NSString *SrvType;
- NSString *SrvName;
- NSString *Name;
-
- ServiceController *fDomainBrowser;
- ServiceController *fServiceBrowser;
- ServiceController *fServiceResolver;
- ServiceController *fAddressResolver;
+ NSMutableArray *_srvtypeKeys;
+ NSMutableArray *_srvnameKeys;
+ NSMutableArray *_sortedServices;
+ NSMutableDictionary *_servicesDict;
+ ServiceController *_serviceBrowser;
+ ServiceController *_serviceResolver;
+ ServiceController *_ipv4AddressResolver;
+ ServiceController *_ipv6AddressResolver;
}
-- (IBAction)handleDomainClick:(id)sender;
-- (IBAction)handleNameClick:(id)sender;
-- (IBAction)handleTypeClick:(id)sender;
- (void)notifyTypeSelectionChange:(NSNotification*)note;
- (void)notifyNameSelectionChange:(NSNotification*)note;
- (IBAction)removeSelected:(id)sender;
- (IBAction)addNewService:(id)sender;
-- (IBAction)update:(NSString *)Type Domain:(NSString *)Domain;
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
-- (IBAction)loadDomains:(id)sender;
+- (IBAction)update:(NSString *)Type;
-- (void)updateBrowseWithResult:(DNSServiceFlags)flags name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain;
-- (void)updateEnumWithResult:(DNSServiceFlags)flags domain:(NSString *)domain;
+- (void)updateBrowseWithName:(const char *)name type:(const char *)resulttype domain:(const char *)domain interface:(uint32_t)interface flags:(DNSServiceFlags)flags;
- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen;
-- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen
- host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome;
+- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen host:(const char*)host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome;
- (void)_cancelPendingResolve;
- (void)_clearResolvedInfo;
// The ServiceController manages cleanup of DNSServiceRef & runloop info for an outstanding request
@interface ServiceController : NSObject
{
- DNSServiceRef fServiceRef;
- CFSocketRef fSocketRef;
- CFRunLoopSourceRef fRunloopSrc;
+ DNSServiceRef fServiceRef;
+ CFSocketRef fSocketRef;
+ CFRunLoopSourceRef fRunloopSrc;
}
-- (id) initWithServiceRef:(DNSServiceRef) ref;
-- (boolean_t) addToCurrentRunLoop;
-- (DNSServiceRef) serviceRef;
-- (void) dealloc;
+- (id)initWithServiceRef:(DNSServiceRef)ref;
+- (void)addToCurrentRunLoop;
+- (DNSServiceRef)serviceRef;
+- (void)dealloc;
@end // interface ServiceController
-static void ProcessSockData( CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
-// CFRunloop callback that notifies dns_sd when new data appears on a DNSServiceRef's socket.
+static void
+ProcessSockData(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
- DNSServiceRef serviceRef = (DNSServiceRef) info;
- DNSServiceErrorType err = DNSServiceProcessResult( serviceRef);
- if ( err != kDNSServiceErr_NoError)
- printf( "DNSServiceProcessResult() returned an error! %d\n", err);
+ DNSServiceRef serviceRef = (DNSServiceRef)info;
+ DNSServiceErrorType err = DNSServiceProcessResult(serviceRef);
+ if (err != kDNSServiceErr_NoError) {
+ printf("DNSServiceProcessResult() returned an error! %d\n", err);
+ }
}
-static void DomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
- DNSServiceErrorType errorCode, const char *replyDomain, void *context )
-// Report newly-discovered domains to the BrowserController.
+
+static void
+ServiceBrowseReply(DNSServiceRef sdRef, DNSServiceFlags servFlags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+ const char *serviceName, const char *regtype, const char *replyDomain, void *context)
{
- if ( errorCode == kDNSServiceErr_NoError) {
- BrowserController *pSelf = (BrowserController*) context;
- [pSelf updateEnumWithResult:flags domain:[NSString stringWithUTF8String:replyDomain]];
+ if (errorCode == kDNSServiceErr_NoError) {
+ [(BrowserController*)context updateBrowseWithName:serviceName type:regtype domain:replyDomain interface:interfaceIndex flags:servFlags];
} else {
- printf( "DomainEnumReply got an error! %d\n", errorCode);
+ printf("ServiceBrowseReply got an error! %d\n", errorCode);
}
}
-static void ServiceBrowseReply( DNSServiceRef sdRef, DNSServiceFlags servFlags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
- const char *serviceName, const char *regtype, const char *replyDomain, void *context )
-// Report newly-discovered services to the BrowserController.
+
+static void
+ServiceResolveReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+ const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
{
- if ( errorCode == kDNSServiceErr_NoError) {
- BrowserController *pSelf = (BrowserController*) context;
- [pSelf updateBrowseWithResult:servFlags name:[NSString stringWithUTF8String:serviceName]
- type:[NSString stringWithUTF8String:regtype] domain:[NSString stringWithUTF8String:replyDomain]];
+ if (errorCode == kDNSServiceErr_NoError) {
+ [(BrowserController*)context resolveClientWitHost:[NSString stringWithUTF8String:hosttarget] port:port interfaceIndex:interfaceIndex txtRecord:txtRecord txtLen:txtLen];
} else {
- printf( "ServiceBrowseReply got an error! %d\n", errorCode);
+ printf("ServiceResolveReply got an error! %d\n", errorCode);
}
}
-static void ServiceResolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
- DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port,
- uint16_t txtLen, const char *txtRecord, void *context )
-// Pass along resolved service info to the BrowserController.
+
+static void
+QueryRecordReply(DNSServiceRef DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+ const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
{
- if ( errorCode == kDNSServiceErr_NoError) {
- BrowserController *pSelf = (BrowserController*) context;
- [pSelf resolveClientWitHost:[NSString stringWithUTF8String:hosttarget] port:port interfaceIndex:interfaceIndex txtRecord:txtRecord txtLen:txtLen];
- } else {
- printf( "ServiceResolveReply got an error! %d\n", errorCode);
- }
+ if (errorCode == kDNSServiceErr_NoError) {
+ [(BrowserController*)context updateAddress:rrtype addr:rdata addrLen:rdlen host:fullname interfaceIndex:interfaceIndex more:(flags & kDNSServiceFlagsMoreComing)];
+ } else {
+ printf("QueryRecordReply got an error! %d\n", errorCode);
+ }
}
-static void QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex,
- DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass,
- uint16_t rdlen, const void *rdata, uint32_t ttl, void *context )
-// DNSServiceQueryRecord callback used to look up IP addresses.
-{
- BrowserController *pBrowser = (BrowserController*) context;
- [pBrowser updateAddress:rrtype addr:rdata addrLen:rdlen host:fullname interfaceIndex:interfaceIndex
- more:((flags & kDNSServiceFlagsMoreComing) != 0)];
+static void
+InterfaceIndexToName(uint32_t interface, char *interfaceName)
+{
+ assert(interfaceName);
+
+ if (interface == kDNSServiceInterfaceIndexAny) {
+ // All active network interfaces.
+ strlcpy(interfaceName, "all", IF_NAMESIZE);
+ } else if (interface == kDNSServiceInterfaceIndexLocalOnly) {
+ // Only available locally on this machine.
+ strlcpy(interfaceName, "local", IF_NAMESIZE);
+ } else {
+ // Converts interface index to interface name.
+ if_indextoname(interface, interfaceName);
+ }
}
{
NSMutableDictionary *regDict = [NSMutableDictionary dictionary];
- NSArray *typeArray = [NSArray arrayWithObjects:@"_ftp._tcp", @"_tftp._tcp",
- @"_ssh._tcp", @"_telnet._tcp",
+ NSArray *typeArray = [NSArray arrayWithObjects:@"_afpovertcp._tcp",
+ @"_smb._tcp",
+ @"_rfb._tcp",
+ @"_ssh._tcp",
+ @"_ftp._tcp",
@"_http._tcp",
- @"_printer._tcp", @"_ipp._tcp",
- @"_ichat._tcp", @"_eppc._tcp",
- @"_afpovertcp._tcp", @"_afpovertcp._tcp", @"_MacOSXDupSuppress._tcp", nil];
- NSArray *nameArray = [NSArray arrayWithObjects:@"File Transfer (ftp)", @"Trivial File Transfer (tftp)",
- @"Secure Shell (ssh)", @"Telnet",
- @"Web Server (http)",
- @"LPR Printer", @"IPP Printer",
- @"iChat", @"Remote AppleEvents",
- @"AppleShare Server", @"SMB File Server", @"Mystery Service", nil];
+ @"_printer._tcp",
+ @"_ipp._tcp",
+ @"_airport._tcp",
+ @"_presence._tcp",
+ @"_daap._tcp",
+ @"_dpap._tcp",
+ nil];
+
+ NSArray *nameArray = [NSArray arrayWithObjects:@"AppleShare Servers",
+ @"Windows Sharing",
+ @"Screen Sharing",
+ @"Secure Shell",
+ @"FTP Servers",
+ @"Web Servers",
+ @"LPR Printers",
+ @"IPP Printers",
+ @"AirPort Base Stations",
+ @"iChat Buddies",
+ @"iTunes Libraries",
+ @"iPhoto Libraries",
+ nil];
[regDict setObject:typeArray forKey:@"SrvTypeKeys"];
[regDict setObject:nameArray forKey:@"SrvNameKeys"];
- (id)init
{
- [self registerDefaults];
-
- fDomainBrowser = nil;
- fServiceBrowser = nil;
- fServiceResolver = nil;
- fAddressResolver = nil;
-
- return [super init];
+ self = [super init];
+ if (self) {
+ _srvtypeKeys = nil;
+ _srvnameKeys = nil;
+ _serviceBrowser = nil;
+ _serviceResolver = nil;
+ _ipv4AddressResolver = nil;
+ _ipv6AddressResolver = nil;
+ _sortedServices = [[NSMutableArray alloc] init];
+ _servicesDict = [[NSMutableDictionary alloc] init];
+ }
+ return self;
}
-- (void)awakeFromNib //BrowserController startup procedure
-{
- SrvType=NULL;
- Domain=NULL;
- srvtypeKeys = [NSMutableArray array]; //Define arrays for Type, Domain, and Name
- srvnameKeys = [NSMutableArray array];
-
- domainKeys = [NSMutableArray array];
- [domainKeys retain];
-
- nameKeys = [NSMutableArray array];
- [nameKeys retain];
- [srvtypeKeys retain]; //Keep arrays in memory until BrowserController closes
- [srvnameKeys retain]; //Keep arrays in memory until BrowserController closes
- [typeField sizeLastColumnToFit]; //Set column sizes to use their whole table's width.
+- (void)awakeFromNib
+{
+ [typeField sizeLastColumnToFit];
[nameField sizeLastColumnToFit];
- [domainField sizeLastColumnToFit];
-// (self is specified as the NSTableViews' data source in the nib)
-
[nameField setDoubleAction:@selector(connect:)];
- // Listen for table selection changes
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyTypeSelectionChange:)
- name:NSTableViewSelectionDidChangeNotification object:typeField];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyNameSelectionChange:)
- name:NSTableViewSelectionDidChangeNotification object:nameField];
-
- //[srvtypeKeys addObject:@"_ftp._tcp"]; //Add supported protocols and domains to their
- //[srvnameKeys addObject:@"File Transfer (ftp)"];
- //[srvtypeKeys addObject:@"_printer._tcp"]; //respective arrays
- //[srvnameKeys addObject:@"Printer (lpr)"];
- //[srvtypeKeys addObject:@"_http._tcp"]; //respective arrays
- //[srvnameKeys addObject:@"Web Server (http)"];
- //[srvtypeKeys addObject:@"_afp._tcp"]; //respective arrays
- //[srvnameKeys addObject:@"AppleShare Server (afp)"];
-
- [self _clearResolvedInfo];
-
- [srvtypeKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"]];
- [srvnameKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"]];
-
-
- [typeField reloadData]; //Reload (redraw) data in fields
- [domainField reloadData];
-
- [self loadDomains:self];
-
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyTypeSelectionChange:) name:NSTableViewSelectionDidChangeNotification object:typeField];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyNameSelectionChange:) name:NSTableViewSelectionDidChangeNotification object:nameField];
+
+ _srvtypeKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"] mutableCopy];
+ _srvnameKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"] mutableCopy];
+
+ if (!_srvtypeKeys || !_srvnameKeys) {
+ [_srvtypeKeys release];
+ [_srvnameKeys release];
+ [self registerDefaults];
+ _srvtypeKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"] mutableCopy];
+ _srvnameKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"] mutableCopy];
+ }
+
+ [typeField reloadData];
}
-- (void)dealloc //Deallocation method
+
+- (void)dealloc
{
- [srvtypeKeys release];
- [srvnameKeys release];
- [nameKeys release];
- [domainKeys release];
+ [_srvtypeKeys release];
+ [_srvnameKeys release];
+ [_servicesDict release];
+ [_sortedServices release];
+ [super dealloc];
}
+
-(void)tableView:(NSTableView *)theTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row
{
- if (row<0) return;
+ if (row < 0) return;
}
+
- (int)numberOfRowsInTableView:(NSTableView *)theTableView //Begin mandatory TableView methods
{
- if (theTableView == typeField)
- {
- return [srvnameKeys count];
- }
- if (theTableView == domainField)
- {
- return [domainKeys count];
+ if (theTableView == typeField) {
+ return [_srvnameKeys count];
}
- if (theTableView == nameField)
- {
- return [nameKeys count];
+ if (theTableView == nameField) {
+ return [_servicesDict count];
}
- if (theTableView == serviceDisplayTable)
- {
- return [srvnameKeys count];
+ if (theTableView == serviceDisplayTable) {
+ return [_srvnameKeys count];
}
return 0;
}
+
- (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)theColumn row:(int)rowIndex
{
- if (theTableView == typeField)
- {
- return [srvnameKeys objectAtIndex:rowIndex];
- }
- if (theTableView == domainField)
- {
- return [domainKeys objectAtIndex:rowIndex];
+ if (theTableView == typeField) {
+ return [_srvnameKeys objectAtIndex:rowIndex];
}
- if (theTableView == nameField)
- {
- return [[nameKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:rowIndex];
+ if (theTableView == nameField) {
+ return [[_servicesDict objectForKey:[_sortedServices objectAtIndex:rowIndex]] name];
}
- if (theTableView == serviceDisplayTable)
- {
+ if (theTableView == serviceDisplayTable) {
if (theColumn == typeColumn) {
- return [srvtypeKeys objectAtIndex:rowIndex];
+ return [_srvtypeKeys objectAtIndex:rowIndex];
}
if (theColumn == nameColumn) {
- return [srvnameKeys objectAtIndex:rowIndex];
+ return [_srvnameKeys objectAtIndex:rowIndex];
}
- return 0;
+ return nil;
}
- else
- return(0);
-} //End of mandatory TableView methods
-
-- (IBAction)handleTypeClick:(id)sender //Handle clicks for Type
-{
- // 3282283: No longer used - update happens in notifyTypeSelectionChange
-}
-
-
-- (IBAction)handleDomainClick:(id)sender //Handle clicks for Domain
-{
- int index=[sender selectedRow]; //Find index of selected row
- if (index==-1) return; //Error checking
- Domain = [domainKeys objectAtIndex:index]; //Save desired Domain
-
- [self _cancelPendingResolve];
-
- if (SrvType!=NULL) [self update:SrvType Domain:Domain]; //If Type and Domain are set, update records
+
+ return nil;
}
-- (IBAction)handleNameClick:(id)sender //Handle clicks for Name
-{
- // 3282283: No longer used - update happens in notifyNameSelectionChange
-}
- (void)notifyTypeSelectionChange:(NSNotification*)note
-/* Called when the selection of the Type table changes */
{
- int index=[[note object] selectedRow]; //Find index of selected row
- if (index==-1) return; //Error checking
- SrvType = [srvtypeKeys objectAtIndex:index]; //Save desired Type
- SrvName = [srvnameKeys objectAtIndex:index]; //Save desired Type
-
[self _cancelPendingResolve];
- [self update:SrvType Domain:Domain]; //If Type and Domain are set, update records
+ int index = [[note object] selectedRow];
+ if (index != -1) {
+ [self update:[_srvtypeKeys objectAtIndex:index]];
+ } else {
+ [self update:nil];
+ }
}
+
- (void)notifyNameSelectionChange:(NSNotification*)note
-/* Called when the selection of the Name table changes */
{
- int index=[[note object] selectedRow]; //Find index of selected row
-
- [self _cancelPendingResolve]; // Cancel any pending Resolve for any table selection change
-
- if (index==-1) {
- Name = nil; // Name may no longer point to a list member
+ [self _cancelPendingResolve];
+
+ int index = [[note object] selectedRow];
+ if (index == -1) {
return;
}
- Name=[[nameKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:index]; //Save desired name
-
- [self _clearResolvedInfo];
-
- DNSServiceRef serviceRef;
- DNSServiceErrorType err;
- err = DNSServiceResolve ( &serviceRef, (DNSServiceFlags) 0, 0, (char *)[Name UTF8String], (char *)[SrvType UTF8String],
- (char *)(Domain?[Domain UTF8String]:""), ServiceResolveReply, self);
- if ( kDNSServiceErr_NoError == err) {
- fServiceResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
- [fServiceResolver addToCurrentRunLoop];
+
+ // Get the currently selected service
+ NSNetService *service = [_servicesDict objectForKey:[_sortedServices objectAtIndex:index]];
+
+ DNSServiceRef serviceRef;
+ DNSServiceErrorType err = DNSServiceResolve(&serviceRef,
+ (DNSServiceFlags)0,
+ kDNSServiceInterfaceIndexAny,
+ (const char *)[[service name] UTF8String],
+ (const char *)[[service type] UTF8String],
+ (const char *)[[service domain] UTF8String],
+ (DNSServiceResolveReply)ServiceResolveReply,
+ self);
+
+ if (kDNSServiceErr_NoError == err) {
+ _serviceResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+ [_serviceResolver addToCurrentRunLoop];
}
}
-- (IBAction)loadDomains:(id)sender
-{
- DNSServiceErrorType err;
- DNSServiceRef serviceRef;
-
- err = DNSServiceEnumerateDomains( &serviceRef, kDNSServiceFlagsBrowseDomains, 0, DomainEnumReply, self);
- if ( kDNSServiceErr_NoError == err) {
- fDomainBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef];
- [fDomainBrowser addToCurrentRunLoop];
- }
- else {
- NSAlert *alert = [NSAlert alertWithMessageText:@"Could not connect to mDNSResponder!"
- defaultButton:@"Quit" alternateButton:nil otherButton:nil informativeTextWithFormat:
- @"Check to see if mDNSResponder is still running."];
- if ( alert != NULL)
- [alert runModal];
- exit( err);
- }
-}
-- (IBAction)update:theType Domain:theDomain; //The Big Kahuna: Fetch PTR records and update application
+- (IBAction)update:(NSString *)theType
{
- const char * DomainC;
- const char * TypeC=[theType UTF8String]; //Type in C string format
-
- DNSServiceErrorType err = kDNSServiceErr_NoError;
-
- if (theDomain) {
- DomainC = [theDomain UTF8String]; //Domain in C string format
- } else {
- DomainC = "";
- }
-
- [nameKeys removeAllObjects]; //Get rid of displayed records if we're going to go get new ones
- [nameField reloadData]; //Reload (redraw) names to show the old data is gone
+ [_servicesDict removeAllObjects];
+ [_sortedServices removeAllObjects];
+ [nameField reloadData];
// get rid of the previous browser if one exists
- if ( fServiceBrowser != nil) {
- [fServiceBrowser release];
- fServiceBrowser = nil;
+ if (_serviceBrowser != nil) {
+ [_serviceBrowser release];
+ _serviceBrowser = nil;
+ }
+
+ if (theType) {
+ DNSServiceRef serviceRef;
+ DNSServiceErrorType err = DNSServiceBrowse(&serviceRef, (DNSServiceFlags)0, 0, [theType UTF8String], NULL, ServiceBrowseReply, self);
+ if (kDNSServiceErr_NoError == err) {
+ _serviceBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef];
+ [_serviceBrowser addToCurrentRunLoop];
+ }
}
-
- // now create a browser to return the values for the nameField ...
- DNSServiceRef serviceRef;
- err = DNSServiceBrowse( &serviceRef, (DNSServiceFlags) 0, 0, TypeC, DomainC, ServiceBrowseReply, self);
- if ( kDNSServiceErr_NoError == err) {
- fServiceBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef];
- [fServiceBrowser addToCurrentRunLoop];
- }
}
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication //Quit when main window is closed
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{
return YES;
}
-- (BOOL)windowShouldClose:(NSWindow *)sender //Save domains to our domain file when quitting
-{
- [domainField reloadData];
- return YES;
-}
-- (void)updateEnumWithResult:(DNSServiceFlags)flags domain:(NSString *)domain
+- (void)updateBrowseWithName:(const char *)name type:(const char *)type domain:(const char *)domain interface:(uint32_t)interface flags:(DNSServiceFlags)flags
{
- if ( ( flags & kDNSServiceFlagsAdd) != 0) { // new domain received
- // add the domain to the list
- [domainKeys addObject:domain];
- } else if (!(flags & kDNSServiceFlagsAdd)) {
- // remove the domain from the list
- NSEnumerator *dmnEnum = [domainKeys objectEnumerator];
- NSString *aDomain = nil;
+ NSString *key = [NSString stringWithFormat:@"%s.%s%s%d", name, type, domain, interface];
+ NSNetService *service = [[NSNetService alloc] initWithDomain:[NSString stringWithUTF8String:domain] type:[NSString stringWithUTF8String:type] name:[NSString stringWithUTF8String:name]];
+
+ if (flags & kDNSServiceFlagsAdd) {
+ [_servicesDict setObject:service forKey:key];
+ } else {
+ [_servicesDict removeObjectForKey:key];
+ }
- while (aDomain = [dmnEnum nextObject]) {
- if ([aDomain isEqualToString:domain]) {
- [domainKeys removeObject:domain];
- break;
- }
+ // If not expecting any more data, then reload (redraw) TableView with newly found data
+ if (!(flags & kDNSServiceFlagsMoreComing)) {
+
+ // Save the current TableView selection
+ int index = [nameField selectedRow];
+ NSString *selected = (index != -1) ? [[_sortedServices objectAtIndex:index] copy] : nil;
+
+ [_sortedServices release];
+ _sortedServices = [[_servicesDict allKeys] mutableCopy];
+ [_sortedServices sortUsingSelector:@selector(caseInsensitiveCompare:)];
+ [nameField reloadData];
+
+ // Restore the previous TableView selection
+ index = selected ? [_sortedServices indexOfObject:selected] : NSNotFound;
+ if (index != NSNotFound) {
+ [nameField selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
+ [nameField scrollRowToVisible:index];
}
+
+ [selected release];
}
- // update the domain table
- [domainField reloadData];
- // Terminate the enumeration once the last domain is delivered.
- if ( ( flags & kDNSServiceFlagsMoreComing) == 0) {
- [fDomainBrowser release];
- fDomainBrowser = nil;
- }
-
- // At some point, we may want to support a TableView for domain browsing. For now, just pick first domain that comes up.
- if ( Domain == nil)
- Domain = [domain retain];
+ [service release];
return;
}
-
-- (void)updateBrowseWithResult:(DNSServiceFlags)flags name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain
+- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen
{
+ DNSServiceRef serviceRef;
- //NSLog(@"Received result %@ %@ %@ %d", name, resulttype, domain, type);
+ if (_ipv4AddressResolver) {
+ [_ipv4AddressResolver release];
+ _ipv4AddressResolver = nil;
+ }
+
+ if (_ipv6AddressResolver) {
+ [_ipv6AddressResolver release];
+ _ipv6AddressResolver = nil;
+ }
- if (!(flags & kDNSServiceFlagsAdd)) {
- if ([nameKeys containsObject:name]) {
- [nameKeys removeObject:name];
+ // Start an async lookup for IPv4 addresses
+ DNSServiceErrorType err = DNSServiceQueryRecord(&serviceRef, (DNSServiceFlags)0, interface, [host UTF8String], kDNSServiceType_A, kDNSServiceClass_IN, QueryRecordReply, self);
+ if (err == kDNSServiceErr_NoError) {
+ _ipv4AddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+ [_ipv4AddressResolver addToCurrentRunLoop];
+ }
- // 3282283: Cancel pending browse if object goes away.
- if ( [name isEqualToString:Name])
- [nameField deselectAll:self];
- }
- }
- else if ( ( flags & kDNSServiceFlagsAdd) != 0) {
- if (![nameKeys containsObject:name]) {
- [nameKeys addObject:name];
- }
+ // Start an async lookup for IPv6 addresses
+ err = DNSServiceQueryRecord(&serviceRef, (DNSServiceFlags)0, interface, [host UTF8String], kDNSServiceType_AAAA, kDNSServiceClass_IN, QueryRecordReply, self);
+ if (err == kDNSServiceErr_NoError) {
+ _ipv6AddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
+ [_ipv6AddressResolver addToCurrentRunLoop];
}
- // If not expecting any more data, then reload (redraw) Name TableView with newly found data
- if ((flags & kDNSServiceFlagsMoreComing) == 0)
- [nameField reloadData];
- return;
-}
-
-- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface
- txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen
-/* Display resolved information about the selected service. */
-{
- DNSServiceErrorType err;
- DNSServiceRef serviceRef;
-
- // Start an async lookup for IPv4 & IPv6 addresses
- if ( fAddressResolver != nil) {
- [fAddressResolver release];
- fAddressResolver = nil;
- }
- err = DNSServiceQueryRecord( &serviceRef, (DNSServiceFlags) 0, interface, [host UTF8String],
- ns_t_a, ns_c_in, QueryRecordReply, self);
- if ( err == kDNSServiceErr_NoError) {
- fAddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
- [fAddressResolver addToCurrentRunLoop];
- }
+ char interfaceName[IF_NAMESIZE];
+ InterfaceIndexToName(interface, interfaceName);
[hostField setStringValue:host];
- [portField setIntValue:port];
+ [interfaceField setStringValue:[NSString stringWithUTF8String:interfaceName]];
+ [portField setIntValue:ntohs(port)];
// kind of a hack: munge txtRecord so it's human-readable
- if ( txtLen > 0) {
- char *readableText = (char*) malloc( txtLen);
- if ( readableText != nil) {
- ByteCount index, subStrLen;
- memcpy( readableText, txtRecord, txtLen);
- for ( index=0; index < txtLen - 1; index += subStrLen + 1) {
- subStrLen = readableText[ index];
- readableText[ index] = '\n';
+ if (txtLen > 0) {
+ char *readableText = (char*) malloc(txtLen);
+ if (readableText != nil) {
+ ByteCount index, subStrLen;
+ memcpy(readableText, txtRecord, txtLen);
+ for (index=0; index < txtLen - 1; index += subStrLen + 1) {
+ subStrLen = readableText[index];
+ readableText[index] = ' ';
}
[textField setStringValue:[NSString stringWithCString:&readableText[1] length:txtLen - 1]];
- free( readableText);
+ free(readableText);
}
}
}
-- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen
- host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome
-/* Update address field(s) with info obtained by fAddressResolver. */
+
+- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome
{
- if ( rrtype == ns_t_a) { // IPv4
- char addrBuff[256];
- inet_ntop( AF_INET, buff, addrBuff, sizeof addrBuff);
- strcat( addrBuff, " ");
+ char addrBuff[256];
+
+ if (rrtype == kDNSServiceType_A) {
+ inet_ntop(AF_INET, buff, addrBuff, sizeof(addrBuff));
+ if ([[ipAddressField stringValue] length] > 0) {
+ [ipAddressField setStringValue:[NSString stringWithFormat:@"%@, ", [ipAddressField stringValue]]];
+ }
[ipAddressField setStringValue:[NSString stringWithFormat:@"%@%s", [ipAddressField stringValue], addrBuff]];
- if ( !moreToCome) {
- [fAddressResolver release];
- fAddressResolver = nil;
-
- // After we find v4 we look for v6
- DNSServiceRef serviceRef;
- DNSServiceErrorType err;
- err = DNSServiceQueryRecord( &serviceRef, (DNSServiceFlags) 0, interface, host,
- ns_t_aaaa, ns_c_in, QueryRecordReply, self);
- if ( err == kDNSServiceErr_NoError) {
- fAddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef];
- [fAddressResolver addToCurrentRunLoop];
- }
+ if (!moreToCome) {
+ [_ipv4AddressResolver release];
+ _ipv4AddressResolver = nil;
}
- }
- else if ( rrtype == ns_t_aaaa) // IPv6
- {
- char addrBuff[256];
- inet_ntop( AF_INET6, buff, addrBuff, sizeof addrBuff);
- strcat( addrBuff, " ");
+ } else if (rrtype == kDNSServiceType_AAAA) {
+ inet_ntop(AF_INET6, buff, addrBuff, sizeof(addrBuff));
+ if ([[ip6AddressField stringValue] length] > 0) {
+ [ip6AddressField setStringValue:[NSString stringWithFormat:@"%@, ", [ip6AddressField stringValue]]];
+ }
[ip6AddressField setStringValue:[NSString stringWithFormat:@"%@%s", [ip6AddressField stringValue], addrBuff]];
- if ( !moreToCome) {
- [fAddressResolver release];
- fAddressResolver = nil;
+ if (!moreToCome) {
+ [_ipv6AddressResolver release];
+ _ipv6AddressResolver = nil;
}
}
}
- (void)connect:(id)sender
{
NSString *host = [hostField stringValue];
- int port = [portField intValue];
NSString *txtRecord = [textField stringValue];
-
- if (!txtRecord) txtRecord = @"";
-
- if (!host || !port) return;
-
- if ([SrvType isEqualToString:@"_http._tcp"])
- {
- NSString *pathDelim = @"path=";
- NSRange where;
+ int port = [portField intValue];
+
+ int index = [nameField selectedRow];
+ NSString *selected = (index >= 0) ? [_sortedServices objectAtIndex:index] : nil;
+ NSString *type = [[_servicesDict objectForKey:selected] type];
+
+ if ([type isEqual:@"_http._tcp."]) {
+ NSString *pathDelim = @"path=";
+ NSRange where;
// If the TXT record specifies a path, extract it.
where = [txtRecord rangeOfString:pathDelim options:NSCaseInsensitiveSearch];
- if ( where.length)
- {
- NSRange targetRange = { where.location + where.length, [txtRecord length] - where.location - where.length };
- NSRange endDelim = [txtRecord rangeOfString:@"\n" options:kNilOptions range:targetRange];
+ if (where.length) {
+ NSRange targetRange = { where.location + where.length, [txtRecord length] - where.location - where.length };
+ NSRange endDelim = [txtRecord rangeOfString:@"\n" options:kNilOptions range:targetRange];
- if ( endDelim.length) // if a delimiter was found, truncate the target range
+ if (endDelim.length) // if a delimiter was found, truncate the target range
targetRange.length = endDelim.location - targetRange.location;
NSString *path = [txtRecord substringWithRange:targetRange];
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d%@", host, port, path]]];
- }
- else
+ } else {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d", host, port]]];
+ }
}
- else if ([SrvType isEqualToString:@"_ftp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/", host, port]]];
- else if ([SrvType isEqualToString:@"_tftp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tftp://%@:%d/", host, port]]];
- else if ([SrvType isEqualToString:@"_ssh._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/", host, port]]];
- else if ([SrvType isEqualToString:@"_telnet._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"telnet://%@:%d/", host, port]]];
- else if ([SrvType isEqualToString:@"_printer._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"lpr://%@:%d/", host, port]]];
- else if ([SrvType isEqualToString:@"_ipp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ipp://%@:%d/", host, port]]];
- else if ([SrvType isEqualToString:@"_afpovertcp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/", host, port]]];
- else if ([SrvType isEqualToString:@"_smb._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/", host, port]]];
+ else if ([type isEqual:@"_ftp._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/", host, port]]];
+ else if ([type isEqual:@"_ssh._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/", host, port]]];
+ else if ([type isEqual:@"_afpovertcp._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/", host, port]]];
+ else if ([type isEqual:@"_smb._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/", host, port]]];
+ else if ([type isEqual:@"_rfb._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"vnc://%@:%d/", host, port]]];
return;
}
+
- (IBAction)handleTableClick:(id)sender
{
//populate the text fields
}
+
- (IBAction)removeSelected:(id)sender
{
// remove the selected row and force a refresh
if (selectedRow) {
- [srvtypeKeys removeObjectAtIndex:selectedRow];
- [srvnameKeys removeObjectAtIndex:selectedRow];
+ [_srvtypeKeys removeObjectAtIndex:selectedRow];
+ [_srvnameKeys removeObjectAtIndex:selectedRow];
- [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
- [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
+ [[NSUserDefaults standardUserDefaults] setObject:_srvtypeKeys forKey:@"SrvTypeKeys"];
+ [[NSUserDefaults standardUserDefaults] setObject:_srvnameKeys forKey:@"SrvNameKeys"];
[typeField reloadData];
[serviceDisplayTable reloadData];
}
}
+
- (IBAction)addNewService:(id)sender
{
// add new entries from the edit fields to the arrays for the defaults
- NSString *newType = [serviceTypeField stringValue];
- NSString *newName = [serviceNameField stringValue];
+ NSString *newType = [serviceTypeField stringValue];
+ NSString *newName = [serviceNameField stringValue];
// 3282283: trim trailing '.' from service type field
if ([newType length] && [newType hasSuffix:@"."])
newType = [newType substringToIndex:[newType length] - 1];
if ([newType length] && [newName length]) {
- [srvtypeKeys addObject:newType];
- [srvnameKeys addObject:newName];
+ [_srvtypeKeys addObject:newType];
+ [_srvnameKeys addObject:newName];
- [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"];
- [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"];
+ [[NSUserDefaults standardUserDefaults] setObject:_srvtypeKeys forKey:@"SrvTypeKeys"];
+ [[NSUserDefaults standardUserDefaults] setObject:_srvnameKeys forKey:@"SrvNameKeys"];
[typeField reloadData];
[serviceDisplayTable reloadData];
}
}
+
- (void)_cancelPendingResolve
-// If there a a Resolve outstanding, cancel it.
{
- if ( fAddressResolver != nil) {
- [fAddressResolver release];
- fAddressResolver = nil;
- }
+ [_ipv4AddressResolver release];
+ _ipv4AddressResolver = nil;
- if ( fServiceResolver != nil) {
- [fServiceResolver release];
- fServiceResolver = nil;
- }
+ [_ipv6AddressResolver release];
+ _ipv6AddressResolver = nil;
+
+ [_serviceResolver release];
+ _serviceResolver = nil;
[self _clearResolvedInfo];
}
+
- (void)_clearResolvedInfo
-// Erase the display of resolved info.
{
[hostField setStringValue:@""];
[ipAddressField setStringValue:@""];
[ip6AddressField setStringValue:@""];
[portField setStringValue:@""];
+ [interfaceField setStringValue:@""];
[textField setStringValue:@""];
}
@implementation ServiceController : NSObject
{
- DNSServiceRef fServiceRef;
- CFSocketRef fSocketRef;
- CFRunLoopSourceRef fRunloopSrc;
+ DNSServiceRef fServiceRef;
+ CFSocketRef fSocketRef;
+ CFRunLoopSourceRef fRunloopSrc;
}
-- (id) initWithServiceRef:(DNSServiceRef) ref
+
+- (id)initWithServiceRef:(DNSServiceRef)ref
{
- [super init];
- fServiceRef = ref;
+ self = [super init];
+ if (self) {
+ fServiceRef = ref;
+ fSocketRef = NULL;
+ fRunloopSrc = NULL;
+ }
return self;
}
-- (boolean_t) addToCurrentRunLoop
-/* Add the service to the current runloop. Returns non-zero on success. */
+
+- (void)addToCurrentRunLoop
{
- CFSocketContext ctx = { 1, (void*) fServiceRef, nil, nil, nil };
+ CFSocketContext context = { 0, (void*)fServiceRef, NULL, NULL, NULL };
- fSocketRef = CFSocketCreateWithNative( kCFAllocatorDefault, DNSServiceRefSockFD( fServiceRef),
- kCFSocketReadCallBack, ProcessSockData, &ctx);
- if ( fSocketRef != nil)
- fRunloopSrc = CFSocketCreateRunLoopSource( kCFAllocatorDefault, fSocketRef, 1);
- if ( fRunloopSrc != nil)
- CFRunLoopAddSource( CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
- else
+ fSocketRef = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(fServiceRef), kCFSocketReadCallBack, ProcessSockData, &context);
+ if (fSocketRef) {
+ // Prevent CFSocketInvalidate from closing DNSServiceRef's socket.
+ CFOptionFlags sockFlags = CFSocketGetSocketFlags(fSocketRef);
+ CFSocketSetSocketFlags(fSocketRef, sockFlags & (~kCFSocketCloseOnInvalidate));
+ fRunloopSrc = CFSocketCreateRunLoopSource(kCFAllocatorDefault, fSocketRef, 0);
+ }
+ if (fRunloopSrc) {
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
+ } else {
printf("Could not listen to runloop socket\n");
-
- return fRunloopSrc != nil;
+ }
}
-- (DNSServiceRef) serviceRef
+
+- (DNSServiceRef)serviceRef
{
return fServiceRef;
}
-- (void) dealloc
-/* Remove service from runloop, deallocate service and associated resources */
+
+- (void)dealloc
{
- if ( fSocketRef != nil) {
- CFSocketInvalidate( fSocketRef); // Note: Also closes the underlying socket
- CFRelease( fSocketRef);
+ if (fSocketRef) {
+ CFSocketInvalidate(fSocketRef); // Note: Also closes the underlying socket
+ CFRelease(fSocketRef);
+
+ // Workaround that gives time to CFSocket's select thread so it can remove the socket from its
+ // FD set before we close the socket by calling DNSServiceRefDeallocate. <rdar://problem/3585273>
+ usleep(1000);
}
- if ( fRunloopSrc != nil) {
- CFRunLoopRemoveSource( CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
- CFRelease( fRunloopSrc);
+ if (fRunloopSrc) {
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode);
+ CFRelease(fRunloopSrc);
}
- DNSServiceRefDeallocate( fServiceRef);
+ DNSServiceRefDeallocate(fServiceRef);
[super dealloc];
}
+
@end // implementation ServiceController
int main(int argc, const char *argv[])
OUTLETS = {
domainField = id;
hostField = id;
+ interfaceField = id;
ip6AddressField = id;
ipAddressField = id;
nameColumn = id;
<string>22 474 271 44 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
- <string>349.0</string>
+ <string>446.1</string>
<key>IBOpenObjects</key>
<array>
- <integer>220</integer>
<integer>201</integer>
+ <integer>220</integer>
</array>
<key>IBSystem Version</key>
- <string>7B85</string>
+ <string>8L2127</string>
</dict>
</plist>
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSServiceReg.m,v $
+Revision 1.16 2006/08/14 23:23:55 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.15 2004/06/05 02:01:08 cheshire
Move DNSServiceRegistration from mDNSMacOSX directory to Clients directory
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ClassFactory.cpp,v $
+Revision 1.3 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:21 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ClassFactory.h,v $
+Revision 1.3 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:21 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ExplorerBar.cpp,v $
+Revision 1.4 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2004/07/26 05:44:08 shersche
remove extraneous debug statement
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ExplorerBar.h,v $
+Revision 1.3 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:21 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ExplorerBarWindow.cpp,v $
+Revision 1.22 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.21 2005/04/06 01:13:07 shersche
<rdar://problem/4066195> Use the product icon instead of globe icon for 'About' link.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ExplorerBarWindow.h,v $
+Revision 1.8 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.7 2005/02/25 19:57:30 shersche
<rdar://problem/4023323> Remove FTP browsing from plugin
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ExplorerPlugin.cpp,v $
+Revision 1.9 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.8 2005/06/30 18:01:54 shersche
<rdar://problem/4130635> Cause IE to rebuild cache so we don't have to reboot following an install.
;
+;
; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
;
-; @APPLE_LICENSE_HEADER_START@
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
;
-; This file contains Original Code and/or Modifications of Original Code
-; as defined in and that are subject to the Apple Public Source License
-; Version 2.0 (the 'License'). You may not use this file except in
-; compliance with the License. Please obtain a copy of the License at
-; http://www.opensource.apple.com/apsl/ and read it before using this
-; file.
+; http://www.apache.org/licenses/LICENSE-2.0
;
-; The Original Code and all software distributed under the License are
-; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-; Please see the License for the specific language governing rights and
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
; limitations under the License.
-;
-; @APPLE_LICENSE_HEADER_END@
;
; Change History (most recent first):
;
; $Log: ExplorerPlugin.def,v $
+; Revision 1.3 2006/08/14 23:24:00 cheshire
+; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+;
; Revision 1.2 2004/07/13 21:24:21 rpantos
; Fix for <rdar://problem/3701120>.
;
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ExplorerPlugin.h,v $
+Revision 1.4 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/01/25 18:35:38 shersche
Declare APIs for obtaining handles to resource modules
BEGIN\r
BLOCK "040904b0"\r
BEGIN\r
- VALUE "CompanyName", "Apple Computer, Inc."\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
VALUE "FileDescription", "Bonjour Explorer Bar"\r
VALUE "FileVersion", MASTER_PROD_VERS_STR\r
VALUE "InternalName", "ExplorerPlugin.dll"\r
Name="Support"\r
Filter="">\r
<File\r
- RelativePath="..\..\mDNSWindows\CommonServices.h">\r
+ RelativePath="..\..\mDNSShared\CommonServices.h">\r
</File>\r
<File\r
- RelativePath="..\..\mDNSWindows\DebugServices.c">\r
+ RelativePath="..\..\mDNSShared\DebugServices.c">\r
</File>\r
<File\r
- RelativePath="..\..\mDNSWindows\DebugServices.h">\r
+ RelativePath="..\..\mDNSShared\DebugServices.h">\r
</File>\r
<File\r
RelativePath="..\..\mDNSWindows\isocode.h">\r
BEGIN\r
BLOCK "040904b0"\r
BEGIN\r
- VALUE "CompanyName", "Apple Computer, Inc."\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
VALUE "FileDescription", "Bonjour Resource Module"\r
VALUE "FileVersion", MASTER_PROD_VERS_STR\r
VALUE "InternalName", "ExplorerPluginLocalized.dll"\r
BEGIN\r
BLOCK "040904b0"\r
BEGIN\r
- VALUE "CompanyName", "Apple Computer, Inc."\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
VALUE "FileDescription", "Bonjour Resource Module"\r
VALUE "FileVersion", MASTER_PROD_VERS_STR\r
VALUE "InternalName", "ExplorerPluginResources.dll"\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: LoginDialog.cpp,v $
+Revision 1.3 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:21 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: LoginDialog.h,v $
+Revision 1.3 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:21 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: StdAfx.cpp,v $
+Revision 1.3 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:21 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: StdAfx.h,v $
+Revision 1.4 2006/08/14 23:24:00 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/10/19 19:50:34 herscher
Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSSDUnitTest.java,v $
+Revision 1.6 2006/08/14 23:24:07 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.5 2006/06/20 23:01:58 rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
Revision 1.4 2004/08/04 01:07:43 rpantos
Update unit test for <rdar://problems/3731579&3731582>.
fRegTest = new RegTest();
new BrowseTest();
new DomainTest();
+ new RegistrarTest();
this.waitForEnd();
}
}
}
+class RegistrarTest extends TermReporter implements RegisterRecordListener
+{
+ public RegistrarTest()
+ {
+ try {
+ byte[] kResponsiblePerson = { 'g','r','o','v','e','r' };
+ fRegistrar = DNSSD.createRecordRegistrar( this);
+ fRegistrar.registerRecord( DNSSD.UNIQUE, 0,
+ "test.registrartest.local", 17 /*ns_t_rp*/, 1, kResponsiblePerson, 3600);
+ } catch( Exception e) { e.printStackTrace(); }
+ }
+
+ public void recordRegistered( DNSRecord record, int flags)
+ {
+ String s = "RegistrarTest result flags:" + String.valueOf( flags);
+ System.out.println( s);
+
+ try {
+ byte[] kResponsiblePerson = { 'e','l','m','o' };
+ record.update( 0, kResponsiblePerson, 3600);
+ record.remove();
+ } catch( Exception e) { e.printStackTrace(); }
+ }
+
+ protected DNSSDRecordRegistrar fRegistrar;
+}
+
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+# -*- tab-width: 4 -*-
+#
# Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
#
-# @APPLE_LICENSE_HEADER_START@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
+# http://www.apache.org/licenses/LICENSE-2.0
#
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
# limitations under the License.
-#
-# @APPLE_LICENSE_HEADER_END@
-#
#
# This Makefile builds .jar files for the DNS-SD Java sample apps.
# You must have the Java support installed.
+# -*- tab-width: 4 -*-
+#
# Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
#
-# @APPLE_LICENSE_HEADER_START@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
+# http://www.apache.org/licenses/LICENSE-2.0
#
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
# limitations under the License.
-#
-# @APPLE_LICENSE_HEADER_END@
#
# $Log: Makefile,v $
+# Revision 1.11 2007/05/29 19:57:33 cheshire
+# Use "-Wall" for stricter compiler warnings
+#
+# Revision 1.10 2006/09/21 00:56:37 cheshire
+# <rdar://problem/4245577> Need 64-bit version of dns-sd command-line tool
+# Add in missing "build/" in targets line for builds other than OS X
+#
+# Revision 1.9 2006/09/18 18:55:39 cheshire
+# <rdar://problem/4245577> Need 64-bit version of dns-sd command-line tool
+#
+# Revision 1.8 2006/08/14 23:23:55 cheshire
+# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+#
+# Revision 1.7 2006/01/06 01:06:17 cheshire
+# <rdar://problem/3978979> Compile library and client programs in one pass
+#
# Revision 1.6 2004/09/24 21:15:26 cheshire
# <rdar://problem/3724985> Library "libmdns" misnamed; should be "libdns_sd"
#
#############################################################################
-
-# If library /usr/lib/libdns_sd.* exists, then link it
-ifneq "$(wildcard /usr/lib/libdns_sd.*)" ""
-LIBS = -ldns_sd
-else
+# On OS X the dns_sd library functions are included in libSystem, which is implicitly linked with every executable
+# If /usr/lib/libSystem.dylib exists, then we're on OS X, so we don't need also to link the "dns_sd" shared library
+ifneq "$(wildcard /usr/lib/libSystem.dylib)" ""
+TARGETS = build/dns-sd build/dns-sd64
LIBS =
+else
+TARGETS = build/dns-sd
+LIBS = -L../mDNSPosix/build/prod/ -ldns_sd
endif
-targets: build/dns-sd
+all: $(TARGETS)
clean:
rm -rf build
mkdir build
build/dns-sd: build dns-sd.c
- cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -o $@
+ cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
+
+build/dns-sd64: build dns-sd.c
+ cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64
+
+# Note, we can make a 'fat' version of dns-sd using 'lipo', as shown below, but we
+# don't, because we don't want or need a 'fat' version of dns-sd, because it will
+# never need to access more than 4GB of data. We build the 64-bit version purely so
+# we have a test tool for making sure that the APIs work properly from 64-bit clients.
+# lipo -create dns-sd dns-sd64 -output dns-sd-fat
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: FirstPage.cpp,v $
+Revision 1.6 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.5 2005/07/07 17:53:20 shersche
Fix problems associated with the CUPS printer workaround fix.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: FirstPage.h,v $
+Revision 1.3 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/07/07 17:53:20 shersche
Fix problems associated with the CUPS printer workaround fix.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: FourthPage.cpp,v $
+Revision 1.8 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.7 2005/07/07 17:53:20 shersche
Fix problems associated with the CUPS printer workaround fix.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: FourthPage.h,v $
+Revision 1.4 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/07/07 17:53:20 shersche
Fix problems associated with the CUPS printer workaround fix.
BEGIN\r
BLOCK "040904e4"\r
BEGIN\r
- VALUE "CompanyName", "Apple Computer, Inc."\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
VALUE "FileDescription", "Bonjour Printer Wizard"\r
VALUE "FileVersion", MASTER_PROD_VERS_STR\r
VALUE "InternalName", "PrinterWizard.exe"\r
Name="Support"\r
Filter="">\r
<File\r
- RelativePath="..\..\mDNSWindows\CommonServices.h">\r
+ RelativePath="..\..\mDNSShared\CommonServices.h">\r
</File>\r
<File\r
- RelativePath="..\..\mDNSWindows\DebugServices.c">\r
+ RelativePath="..\..\mDNSShared\DebugServices.c">\r
</File>\r
<File\r
- RelativePath="..\..\mDNSWindows\DebugServices.h">\r
+ RelativePath="..\..\mDNSShared\DebugServices.h">\r
</File>\r
<File\r
RelativePath="..\..\mDNSShared\dns_sd.h">\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: PrinterSetupWizardApp.cpp,v $
+Revision 1.9 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.8 2005/04/13 17:43:39 shersche
<rdar://problem/4081448> Change "PrinterWizard.dll" to "PrinterWizardResources.dll"
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: PrinterSetupWizardApp.h,v $
+Revision 1.3 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/01/25 08:52:55 shersche
<rdar://problem/3911084> Add APIs to return localizable and non-localizable resource DLL handles
Bug #: 3911084
BEGIN\r
BLOCK "040904e4"\r
BEGIN\r
- VALUE "CompanyName", "Apple Computer, Inc."\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
VALUE "FileDescription", "Bonjour Resource Module"\r
VALUE "FileVersion", MASTER_PROD_VERS_STR\r
VALUE "InternalName", "PrinterWizardLocalized.dll"\r
BEGIN\r
BLOCK "040904e4"\r
BEGIN\r
- VALUE "CompanyName", "Apple Computer, Inc."\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
VALUE "FileDescription", "Bonjour Resource Module"\r
VALUE "FileVersion", MASTER_PROD_VERS_STR\r
VALUE "InternalName", "PrinterWizardLocalized.dll"\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: PrinterSetupWizardSheet.cpp,v $
+Revision 1.35 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.34 2005/10/05 17:32:51 herscher
<rdar://problem/4141221> Use a case insensitive compare operation to check whether a printer with the same name has already been installed.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: PrinterSetupWizardSheet.h,v $
+Revision 1.12 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.11 2005/10/05 17:32:51 herscher
<rdar://problem/4141221> Use a case insensitive compare operation to check whether a printer with the same name has already been installed.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: SecondPage.cpp,v $
+Revision 1.19 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.18 2005/07/20 17:44:54 shersche
<rdar://problem/4124524> UI fixes for CUPS workaround
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: SecondPage.h,v $
+Revision 1.9 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.8 2005/03/20 20:08:37 shersche
<rdar://problem/4055670> Second screen should not select a printer by default
SetPrinterInformationState( BOOL state );
std::string m_selectedName;
-\r
-private:\r
-\r
- CStatic m_printerInformation;\r
- CStatic m_descriptionLabel;\r
- CStatic m_descriptionField;\r
- CStatic m_locationLabel;\r
- CStatic m_locationField;\r
+
+
+private:
+
+
+
+ CStatic m_printerInformation;
+
+ CStatic m_descriptionLabel;
+
+ CStatic m_descriptionField;
+
+ CStatic m_locationLabel;
+
+ CStatic m_locationField;
+
bool m_gotChoice;
};
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ThirdPage.cpp,v $
+Revision 1.37 2007/06/08 06:30:26 herscher
+<rdar://problem/5257700> Fix uninitialized pointers when detecting generic PCL and PS drivers
+
+Revision 1.36 2007/06/06 20:39:10 cheshire
+<rdar://problem/5254377> Printer Setup Wizard started crashing in Bonjour104A8, after update to Visual Studio 2005
+
+Revision 1.35 2007/06/06 20:08:01 cheshire
+<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+AutoScroll model list as well as manufacturer list
+
+Revision 1.34 2007/06/06 19:53:48 cheshire
+<rdar://problem/5187308> Move build train to Visual Studio 2005
+
+Revision 1.33 2007/04/20 22:58:10 herscher
+<rdar://problem/4826126> mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2
+
+Revision 1.32 2007/04/13 23:42:20 herscher
+<rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
+
+Revision 1.31 2007/04/13 21:38:46 herscher
+<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+
+Revision 1.30 2007/04/13 20:23:40 herscher
+Fixed mistake in previous checkin that reverted license text for this file
+
+Revision 1.29 2007/04/13 18:10:24 herscher
+<rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
+
+Revision 1.28 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.27 2005/10/05 21:41:45 herscher
<rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS shared queue supports raw
Revision 1.1 2004/06/18 04:36:58 rpantos
First checked in
-
-
*/
#include "stdafx.h"
// local variable is initialize but not referenced
#pragma warning(disable:4189)
-
//
// This is the printer description file that is shipped
-// with Windows
+// with Windows XP and below
//
#define kNTPrintFile L"inf\\ntprint.inf"
+//
+// Windows Vista ships with a set of prn*.inf files
+//
+#define kVistaPrintFiles L"inf\\prn*.inf"
+
//
// These are pre-defined names for Generic manufacturer and model
//
#define kGenericPCLColorDriver L"HP Color LaserJet 4550 PCL"
#define kGenericPCLDriver L"HP LaserJet 4050 Series PCL"
-
//
// states for parsing ntprint.inf
//
ParsingStrings
};
-
// CThirdPage dialog
IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage)
CThirdPage::CThirdPage()
: CPropertyPage(CThirdPage::IDD),
+ m_manufacturerSelected( NULL ),
+ m_modelSelected( NULL ),
+ m_genericPostscript( NULL ),
+ m_genericPCL( NULL ),
m_initialized(false),
m_printerImage( NULL )
{
static const int bufferSize = 32768;
TCHAR windowsDirectory[bufferSize];
CString header;
+ WIN32_FIND_DATA findFileData;
+ HANDLE findHandle;
+ CString prnFiles;
CString ntPrint;
OSStatus err;
BOOL ok;
err = translate_errno( ok, errno_compat(), kUnknownErr );
require_noerr( err, exit );
- ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile);
- err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false );
- require_noerr(err, exit);
+ //
+ // <rdar://problem/4826126>
+ //
+ // If there are no *prn.inf files, we'll assume that the information
+ // is in ntprint.inf
+ //
+ prnFiles.Format( L"%s\\%s", windowsDirectory, kVistaPrintFiles );
+ findHandle = FindFirstFile( prnFiles, &findFileData );
+
+ if ( findHandle != INVALID_HANDLE_VALUE )
+ {
+ CString absolute;
+
+ absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
+ err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
+ require_noerr( err, exit );
+
+ while ( FindNextFile( findHandle, &findFileData ) )
+ {
+ absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
+ err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
+ require_noerr( err, exit );
+ }
+
+ FindClose( findHandle );
+ }
+ else
+ {
+ ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile);
+ err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false );
+ require_noerr(err, exit);
+ }
//
// load printer drivers that have been installed on this machine
return;
}
-
CThirdPage::~CThirdPage()
{
//
}
}
-
// ----------------------------------------------------
// SelectMatch
//
// SelectMatch will do all the UI work associated with
// selected a manufacturer and model of printer. It also
-// makes sure the printer object is update with the
+// makes sure the printer object is update with the
// latest settings
//
// ----------------------------------------------------
if (nIndex != -1)
{
m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
- m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE);
+ //
+ //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+ //
+ AutoScroll(m_manufacturerListCtrl, nIndex);
}
//
if (nIndex != -1)
{
m_modelListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
- m_modelListCtrl.EnsureVisible(nIndex, FALSE);
+ AutoScroll( m_modelListCtrl, nIndex );
m_modelListCtrl.SetFocus();
}
CopyPrinterSettings( printer, service, manufacturer, model );
}
-
void
CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model)
{
SelectMatch( printer, service, manufacturer, model );
}
-
// --------------------------------------------------------
// CopyPrinterSettings
//
}
}
+// --------------------------------------------------------
+// DefaultPrinterExists
+//
+// Checks to see if a default printer has been configured
+// on this machine
+// --------------------------------------------------------
+BOOL
+CThirdPage::DefaultPrinterExists()
+{
+ CPrintDialog dlg(FALSE);
+
+ dlg.m_pd.Flags |= PD_RETURNDEFAULT;
+
+ return dlg.GetDefaults();
+}
+
+// --------------------------------------------------------
+// AutoScroll
+//
+// Ensure selected item is in middle of list
+// --------------------------------------------------------
+void
+CThirdPage::AutoScroll( CListCtrl & list, int nIndex )
+{
+ //
+ //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+ //
+
+ int top;
+ int count;
+
+ list.EnsureVisible( nIndex, FALSE );
+
+ top = list.GetTopIndex();
+ count = list.GetCountPerPage();
+
+ if ( ( nIndex == top ) || ( ( nIndex + 1 ) == ( top + count ) ) )
+ {
+ CRect rect;
+ int rows;
+
+ rows = ( count / 2 );
+
+ if ( nIndex == top )
+ {
+ list.GetItemRect(0, rect, LVIR_BOUNDS);
+ list.Scroll( CPoint( 0, rows * rect.Height() * -1 ) );
+ }
+ else
+ {
+ list.GetItemRect(0, rect, LVIR_BOUNDS);
+ list.Scroll( CPoint( 0, rows * rect.Height() ) );
+ }
+ }
+}
// ------------------------------------------------------
// LoadPrintDriverDefsFromFile
// easy format. Tags are strings that are enclosed in brackets.
// We are only interested in [MANUFACTURERS] and models.
//
-// The only potentially opaque thing about this function is the
+// The only potentially opaque thing about this function is the
// checkForDuplicateModels flag. The problem here is that ntprint.inf
// doesn't contain duplicate models, and it has hundreds of models
// listed. You wouldn't check for duplicates there. But oftentimes,
}
else
{
+ CString name;
+ int curPos;
+
+ //
// remove the leading and trailing delimiters
//
s.Remove('[');
s.Remove(']');
+ //
+ // <rdar://problem/4826126>
+ //
+ // Ignore decorations in model declarations
+ //
+ curPos = 0;
+ name = s.Tokenize( L".", curPos );
+
+ //
// check to see if this is a printer entry
//
- iter = manufacturers.find(s);
+ iter = manufacturers.find( name );
if (iter != manufacturers.end())
{
// if we're parsing manufacturers, then we will parse
// an entry of the form key=val, where key is a delimited
// string specifying a manufacturer name, and val is
- // a tag that is used later in the file. the key is
+ // a tag that is used later in the file. the key is
// delimited by either '"' (quotes) or '%' (percent sign).
//
// the tag is used further down the file when models are
curPos = 0;
val = val.Tokenize(L",", curPos);
+ for ( ;; )
+ {
+ CString decoration;
+
+ decoration = val.Tokenize( L",", curPos );
+
+ if ( decoration.GetLength() > 0 )
+ {
+ manufacturer->decorations.push_back( decoration );
+ }
+ else
+ {
+ break;
+ }
+ }
+
manufacturer->name = NormalizeManufacturerName( key );
manufacturer->tag = val;
}
}
+ //
+ // Stock Vista printer inf files embed guids in the model
+ // declarations for Epson printers. Let's ignore those.
+ //
+ if ( name.Find( L"{", 0 ) != -1 )
+ {
+ continue;
+ }
+
try
{
model = new Model;
return (err);
}
-
// -------------------------------------------------------
// LoadPrintDriverDefs
//
//
// skip over anything that doesn't have a manufacturer field. This
- // fixes a bug that I noticed that occurred after I installed
+ // fixes a bug that I noticed that occurred after I installed
// ProComm. This program add a print driver with no manufacturer
// that screwed up this wizard.
//
return err;
}
-
// -------------------------------------------------------
// LoadGenericPrintDriverDefs
//
// First try and find our generic driver names
iter = m_manufacturers.find(L"HP");
- require_action( iter != manufacturers.end(), exit, err = kUnknownErr );
+ require_action( iter != m_manufacturers.end(), exit, err = kUnknownErr );
manufacturer = iter->second;
- // Look for Postscript
+ // Look for Postscript
model = manufacturer->find( kGenericPSColorDriver );
if ( model )
{
psDriverName = model->name;
-
}
// Look for PCL
if ( model )
{
- pclDriverName = model->name;
+ pclDriverName = model->name;
}
// If we found either a generic PS driver, or a generic PCL driver,
// ------------------------------------------------------
// ConvertToManufacturerName
//
-// This function is responsible for tweaking the
+// This function is responsible for tweaking the
// name so that subsequent string operations won't fail because
// of capitalizations/different names for the same manufacturer
// (i.e. Hewlett-Packard/HP/Hewlett Packard)
return lower;
}
-
// ------------------------------------------------------
// ConvertToModelName
//
return lower;
}
-
// ------------------------------------------------------
// NormalizeManufacturerName
//
return normalized;
}
-
// -------------------------------------------------------
// MatchPrinter
//
hasGenericDriver = true;
}
- // <rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS
+ // <rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS
// shared queue supports raw
if ( q->pdl.Find( L"application/octet-stream" ) != -1 )
if ( useCUPSWorkaround && printer->isSharedFromOSX && hasGenericDriver )
{
- SelectMatch(manufacturers, printer, service, genericManufacturer, genericModel );
+ //
+ // <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
+ //
+ Manufacturers genericManufacturers;
+
+ LoadGenericPrintDriverDefs( genericManufacturers );
+
+ SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
}
else
{
text.LoadString(IDS_PRINTER_MATCH_GOOD);
}
else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) )
- {
+ {
if ( printer->isSharedFromOSX )
{
+ //
+ // <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
+ //
+ Manufacturers genericManufacturers;
+
+ LoadGenericPrintDriverDefs( genericManufacturers );
+
+ SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
+
text.LoadString(IDS_PRINTER_MATCH_GOOD);
}
else
{
+ SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel );
text.LoadString(IDS_PRINTER_MATCH_MAYBE);
}
-
- SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel );
}
else
{
if (nIndex != -1)
{
m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
- m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE);
+
+ //
+ //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+ //
+ AutoScroll(m_manufacturerListCtrl, nIndex);
}
}
}
return err;
}
-
// ------------------------------------------------------
// MatchManufacturer
//
return NULL;
}
-
// -------------------------------------------------------
// MatchModel
//
return NULL;
}
-
// -------------------------------------------------------
// MatchGeneric
//
pdl = q->pdl;
pdl.MakeLower();
- if ( pdl.Find( kPDLPCLKey ) != -1 )
+ if ( m_genericPCL && ( pdl.Find( kPDLPCLKey ) != -1 ) )
{
*model = m_genericPCL;
ok = TRUE;
}
- else if ( pdl.Find( kPDLPostscriptKey ) != -1 )
+ else if ( m_genericPostscript && ( pdl.Find( kPDLPostscriptKey ) != -1 ) )
{
*model = m_genericPostscript;
ok = TRUE;
return ok;
}
-
// -----------------------------------------------------------
// OnInitPage
//
OSStatus err = kNoErr;
// Load printer icon
-
-
-
check( m_printerImage == NULL );
- m_printerImage = (CStatic*) GetDlgItem( IDR_MANIFEST );
+ m_printerImage = (CStatic*) GetDlgItem( 1 ); // 1 == IDR_MANIFEST
check( m_printerImage );
if ( m_printerImage != NULL )
//
//
- // we have to make sure that we only do this once. Typically,
+ // we have to make sure that we only do this once. Typically,
// we would do this in something like OnInitDialog, but we don't
// have this in Wizards, because the window is a PropertySheet.
// We're considered fully initialized when we receive the first
return (err);
}
-
void CThirdPage::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
}
-
// ----------------------------------------------------------
// OnSetActive
//
m_initialized = true;
}
+ //
+ // <rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
+ //
+ if ( DefaultPrinterExists() )
+ {
+ m_defaultPrinterCtrl.SetCheck( BST_UNCHECKED );
+ printer->deflt = false;
+ }
+ else
+ {
+ m_defaultPrinterCtrl.SetCheck( BST_CHECKED );
+ printer->deflt = true;
+ }
+
//
// update the UI with the printer name
//
return CPropertyPage::OnSetActive();
}
-
BOOL
CThirdPage::OnKillActive()
{
CPrinterSetupWizardSheet * psheet;
psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
- require_quiet( psheet, exit );
+ require_quiet( psheet, exit );
psheet->SetLastPage(this);
return CPropertyPage::OnKillActive();
}
-
// -------------------------------------------------------
// PopulateUI
//
return 0;
}
-
BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MANUFACTURER, OnLvnItemchangedManufacturer)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MODEL, OnLvnItemchangedPrinterModel)
ON_BN_CLICKED(IDC_HAVE_DISK, OnBnClickedHaveDisk)
END_MESSAGE_MAP()
-
// CThirdPage message handlers
void CThirdPage::OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult)
{
*pResult = 0;
}
-
void CThirdPage::OnBnClickedDefaultPrinter()
{
CPrinterSetupWizardSheet * psheet;
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ThirdPage.h,v $
+Revision 1.9 2007/04/13 23:42:20 herscher
+<rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
+
+Revision 1.8 2007/04/13 21:38:46 herscher
+<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+
+Revision 1.7 2007/04/13 20:18:30 herscher
+<rdar://problem/4189721> mDNS: Epson shows up twice in the list
+
+Revision 1.6 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.5 2005/07/07 17:53:20 shersche
Fix problems associated with the CUPS printer workaround fix.
private:
- typedef std::map<CString, Manufacturer*> Manufacturers;
+ //
+ //<rdar://problem/4189721> mDNS: Epson shows up twice in the list. Use case insensitive compare
+ //
+ struct compare_func
+ {
+ bool operator()( const CString & s1, const CString & s2 ) const
+ {
+ return s1.CompareNoCase( s2 ) < 0;
+ }
+ };
+
+ typedef std::map<CString, Manufacturer*, compare_func> Manufacturers;
//
// LoadPrintDriverDefsFromFile
void SelectMatch(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model);
void SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model);
void CopyPrinterSettings(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model);
+ //
+ // <rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
+ //
+ BOOL DefaultPrinterExists();
+ //
+ //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
+ //
+ void AutoScroll(CListCtrl & list, int nIndex);
Manufacturers m_manufacturers;
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: UtilTypes.h,v $
+Revision 1.16 2007/04/20 22:58:10 herscher
+<rdar://problem/4826126> mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2
+
+Revision 1.15 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.14 2005/06/30 18:02:54 shersche
<rdar://problem/4124524> Workaround for Mac OS X Printer Sharing bug
typedef std::list<Printer*> Printers;
typedef std::list<Service*> Services;
typedef std::list<Model*> Models;
+ typedef std::list<CString> Decorations;
struct Printer
{
CString name;
CString tag;
Models models;
+ Decorations decorations;
Model*
find( const CString & name );
-/*\r
+/* -*- Mode: C; tab-width: 4 -*-\r
+ *\r
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.\r
*\r
- * @APPLE_LICENSE_HEADER_START@\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
* \r
- * This file contains Original Code and/or Modifications of Original Code\r
- * as defined in and that are subject to the Apple Public Source License\r
- * Version 2.0 (the 'License'). You may not use this file except in\r
- * compliance with the License. Please obtain a copy of the License at\r
- * http://www.opensource.apple.com/apsl/ and read it before using this\r
- * file.\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
* \r
- * The Original Code and all software distributed under the License are\r
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\r
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\r
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\r
- * Please see the License for the specific language governing rights and\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
* limitations under the License.\r
- * \r
- * @APPLE_LICENSE_HEADER_END@\r
\r
Change History (most recent first):\r
\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: stdafx.cpp,v $
+Revision 1.2 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/06/18 04:36:58 rpantos
First checked in
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: stdafx.h,v $
+Revision 1.3 2006/08/14 23:24:09 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/10/19 19:50:35 herscher
Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
-/*\r
+/* -*- Mode: C; tab-width: 4 -*-\r
+ *\r
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.\r
*\r
- * @APPLE_LICENSE_HEADER_START@\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
* \r
- * This file contains Original Code and/or Modifications of Original Code\r
- * as defined in and that are subject to the Apple Public Source License\r
- * Version 2.0 (the 'License'). You may not use this file except in\r
- * compliance with the License. Please obtain a copy of the License at\r
- * http://www.opensource.apple.com/apsl/ and read it before using this\r
- * file.\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
* \r
- * The Original Code and all software distributed under the License are\r
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\r
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\r
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\r
- * Please see the License for the specific language governing rights and\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
* limitations under the License.\r
- * \r
- * @APPLE_LICENSE_HEADER_END@\r
\r
Change History (most recent first):\r
\r
$Log: AssemblyInfo.cs,v $
+Revision 1.2 2006/08/14 23:24:21 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/07/19 07:57:08 shersche
Initial revision
\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: SimpleChat.cs,v $
+Revision 1.6 2006/08/14 23:24:21 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.5 2004/09/13 19:37:42 shersche
Change code to reflect namespace and type changes to dnssd.NET library
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
*
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
* ("Apple") in consideration of your agreement to the following terms, and your
gcc dns-sd.c -o dns-sd -I../mDNSShared -ldns_sd
Windows:
-cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT -DNOT_HAVE_SETLINEBUF ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib
+cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib
(may require that you run a Visual Studio script such as vsvars32.bat first)
*/
-#include "dns_sd.h"
+// For testing changes to dnssd_clientstub.c, uncomment this line and the code will be compiled
+// with an embedded copy of the client stub instead of linking the system library version at runtime.
+// This also useful to work around link errors when you're working on an older version of Mac OS X,
+// and trying to build a newer version of the "dns-sd" command which uses new API entry points that
+// aren't in the system's /usr/lib/libSystem.dylib.
+//#define TEST_NEW_CLIENTSTUB 1
+
#include <ctype.h>
#include <stdio.h> // For stdout, stderr
#include <stdlib.h> // For exit()
#include <string.h> // For strlen(), strcpy(), bzero()
-#include <errno.h> // For errno, EINTR
+#include <errno.h> // For errno, EINTR
#include <time.h>
-#include <sys/types.h> // For u_char
+#include <sys/types.h> // For u_char
#ifdef _WIN32
-#include <process.h>
-typedef int pid_t;
-#define getpid _getpid
-#define strcasecmp _stricmp
-#define snprintf _snprintf
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ #include <process.h>
+ typedef int pid_t;
+ #define getpid _getpid
+ #define strcasecmp _stricmp
+ #define snprintf _snprintf
+ static const char kFilePathSep = '\\';
#else
-#include <sys/time.h> // For struct timeval
-#include <unistd.h> // For getopt() and optind
-#include <arpa/inet.h> // For inet_addr()
+ #include <unistd.h> // For getopt() and optind
+ #include <netdb.h> // For getaddrinfo()
+ #include <sys/time.h> // For struct timeval
+ #include <sys/socket.h> // For AF_INET
+ #include <netinet/in.h> // For struct sockaddr_in()
+ #include <arpa/inet.h> // For inet_addr()
+ #include <net/if.h> // For if_nametoindex()
+ static const char kFilePathSep = '/';
+#endif
+
+#if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE))
+#define __APPLE_API_PRIVATE 1
#endif
+#include "dns_sd.h"
+
+#if TEST_NEW_CLIENTSTUB
+#include "../mDNSShared/dnssd_ipc.c"
+#include "../mDNSShared/dnssd_clientlib.c"
+#include "../mDNSShared/dnssd_clientstub.c"
+#endif
+
+// The "+0" is to cope with the case where _DNS_SD_H is defined but empty (e.g. on Mac OS X 10.4 and earlier)
+#if _DNS_SD_H+0 >= 116
+#define HAS_NAT_PMP_API 1
+#define HAS_ADDRINFO_API 1
+#else
+#define kDNSServiceFlagsReturnIntermediates 0
+#endif
//*************************************************************************************************************
// Globals
static int operation;
static uint32_t opinterface = kDNSServiceInterfaceIndexAny;
-static DNSServiceRef client = NULL;
-static DNSServiceRef client2 = NULL;
+static DNSServiceRef client = NULL;
+static DNSServiceRef client_pa = NULL; // DNSServiceRef for RegisterProxyAddressRecord
+static DNSServiceRef sc1, sc2, sc3; // DNSServiceRefs for kDNSServiceFlagsShareConnection testing
+
static int num_printed;
static char addtest = 0;
static DNSRecordRef record = NULL;
static char myhinfoW[14] = "\002PC\012Windows XP";
static char myhinfoX[ 9] = "\003Mac\004OS X";
static char updatetest[3] = "\002AA";
-static char bigNULL[4096];
+static char bigNULL[8200];
// Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
#define LONG_TIME 100000000
static volatile int timeOut = LONG_TIME;
//*************************************************************************************************************
-// Supporting Utility Function
+// Supporting Utility Functions
static uint16_t GetRRType(const char *s)
{
else return(atoi(s));
}
+#if HAS_NAT_PMP_API | HAS_ADDRINFO_API
+static DNSServiceProtocol GetProtocol(const char *s)
+ {
+ if (!strcasecmp(s, "v4" )) return(kDNSServiceProtocol_IPv4);
+ else if (!strcasecmp(s, "v6" )) return(kDNSServiceProtocol_IPv6);
+ else if (!strcasecmp(s, "v4v6" )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
+ else if (!strcasecmp(s, "v6v4" )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
+ else if (!strcasecmp(s, "udp" )) return(kDNSServiceProtocol_UDP);
+ else if (!strcasecmp(s, "tcp" )) return(kDNSServiceProtocol_TCP);
+ else if (!strcasecmp(s, "udptcp" )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
+ else if (!strcasecmp(s, "tcpudp" )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
+ else return(atoi(s));
+ }
+#endif
+
//*************************************************************************************************************
// Sample callback functions for each of the operation types
return(cstr);
}
-static void DNSSD_API enum_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex,
+static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex,
DNSServiceErrorType errorCode, const char *replyDomain, void *context)
{
+ DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault);
int labels = 0, depth = 0, i, initial = 0;
char text[64];
const char *label[128];
- (void)client; // Unused
+ (void)sdref; // Unused
(void)ifIndex; // Unused
- (void)errorCode; // Unused
(void)context; // Unused
-
- if (!*replyDomain) return;
// 1. Print the header
if (num_printed++ == 0) printf("Timestamp Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
printtimestamp();
- printf("%-10s", DomainMsg(flags));
- printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
- flags &= ~kDNSServiceFlagsMoreComing;
- flags &= ~kDNSServiceFlagsAdd;
- flags &= ~kDNSServiceFlagsDefault;
- if (flags) printf("Flags: %4X ", flags);
- else printf(" ");
-
- // 2. Count the labels
- while (*replyDomain)
+ if (errorCode)
+ printf("Error code %d\n", errorCode);
+ else if (!*replyDomain)
+ printf("Error: No reply domain\n");
+ else
{
- label[labels++] = replyDomain;
- replyDomain = GetNextLabel(replyDomain, text);
- }
+ printf("%-10s", DomainMsg(flags));
+ printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
+ if (partialflags) printf("Flags: %4X ", partialflags);
+ else printf(" ");
+
+ // 2. Count the labels
+ while (*replyDomain)
+ {
+ label[labels++] = replyDomain;
+ replyDomain = GetNextLabel(replyDomain, text);
+ }
+
+ // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
+ if (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
+ else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
+ else initial = 1;
+ labels -= initial;
- // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
- if (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
- else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
- else initial = 1;
- labels -= initial;
-
- // 4. Print the initial one-, two- or three-label clump
- for (i=0; i<initial; i++)
- {
- GetNextLabel(label[labels+i], text);
- if (i>0) printf(".");
- printf("%s", text);
- }
- printf("\n");
-
- // 5. Print the remainder of the hierarchy
- for (depth=0; depth<labels; depth++)
- {
- printf(" ");
- for (i=0; i<=depth; i++) printf("- ");
- GetNextLabel(label[labels-1-depth], text);
- printf("> %s\n", text);
+ // 4. Print the initial one-, two- or three-label clump
+ for (i=0; i<initial; i++)
+ {
+ GetNextLabel(label[labels+i], text);
+ if (i>0) printf(".");
+ printf("%s", text);
+ }
+ printf("\n");
+
+ // 5. Print the remainder of the hierarchy
+ for (depth=0; depth<labels; depth++)
+ {
+ printf(" ");
+ for (i=0; i<=depth; i++) printf("- ");
+ GetNextLabel(label[labels-1-depth], text);
+ printf("> %s\n", text);
+ }
}
- fflush( stdout );
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
-static void DNSSD_API browse_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
+static void DNSSD_API browse_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
const char *replyName, const char *replyType, const char *replyDomain, void *context)
{
char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
- (void)client; // Unused
- (void)errorCode; // Unused
+ (void)sdref; // Unused
(void)context; // Unused
- if (num_printed++ == 0) printf("Timestamp A/R Flags if %-24s %-24s %s\n", "Domain", "Service Type", "Instance Name");
+ if (num_printed++ == 0) printf("Timestamp A/R Flags if %-25s %-25s %s\n", "Domain", "Service Type", "Instance Name");
printtimestamp();
- printf("%s%6X%3d %-24s %-24s %s\n", op, flags, ifIndex, replyDomain, replyType, replyName);
- fflush( stdout );
+ if (errorCode) printf("Error code %d\n", errorCode);
+ else printf("%s%6X%3d %-25s %-25s %s\n", op, flags, ifIndex, replyDomain, replyType, replyName);
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+
+ // To test selective cancellation of operations of shared sockets,
+ // cancel the current operation when we've got a multiple of five results
+ //if (operation == 'S' && num_printed % 5 == 0) DNSServiceRefDeallocate(sdref);
+ }
+
+static void ShowTXTRecord(uint16_t txtLen, const unsigned char *txtRecord)
+ {
+ const unsigned char *ptr = txtRecord;
+ const unsigned char *max = txtRecord + txtLen;
+ while (ptr < max)
+ {
+ const unsigned char *const end = ptr + 1 + ptr[0];
+ if (end > max) { printf("<< invalid data >>"); break; }
+ if (++ptr < end) printf(" "); // As long as string is non-empty, begin with a space
+ while (ptr<end)
+ {
+ // We'd like the output to be shell-friendly, so that it can be copied and pasted unchanged into a "dns-sd -R" command.
+ // However, this is trickier than it seems. Enclosing a string in double quotes doesn't necessarily make it
+ // shell-safe, because shells still expand variables like $foo even when they appear inside quoted strings.
+ // Enclosing a string in single quotes is better, but when using single quotes even backslash escapes are ignored,
+ // meaning there's simply no way to represent a single quote (or apostrophe) inside a single-quoted string.
+ // The only remaining solution is not to surround the string with quotes at all, but instead to use backslash
+ // escapes to encode spaces and all other known shell metacharacters.
+ // (If we've missed any known shell metacharacters, please let us know.)
+ // In addition, non-printing ascii codes (0-31) are displayed as \xHH, using a two-digit hex value.
+ // Because '\' is itself a shell metacharacter (the shell escape character), it has to be escaped as "\\" to survive
+ // the round-trip to the shell and back. This means that a single '\' is represented here as EIGHT backslashes:
+ // The C compiler eats half of them, resulting in four appearing in the output.
+ // The shell parses those four as a pair of "\\" sequences, passing two backslashes to the "dns-sd -R" command.
+ // The "dns-sd -R" command interprets this single "\\" pair as an escaped literal backslash. Sigh.
+ if (strchr(" &;`'\"|*?~<>^()[]{}$", *ptr)) printf("\\");
+ if (*ptr == '\\') printf("\\\\\\\\");
+ else if (*ptr >= ' ' ) printf("%c", *ptr);
+ else printf("\\\\x%02X", *ptr);
+ ptr++;
+ }
+ }
}
-static void DNSSD_API resolve_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
- const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const char *txtRecord, void *context)
+static void DNSSD_API resolve_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
+ const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txtRecord, void *context)
{
- const char *src = txtRecord;
union { uint16_t s; u_char b[2]; } port = { opaqueport };
uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
- (void)client; // Unused
+ (void)sdref; // Unused
(void)ifIndex; // Unused
- (void)errorCode; // Unused
- (void)txtLen; // Unused
(void)context; // Unused
printtimestamp();
- printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber);
-
- if (flags) printf(" Flags: %X", flags);
- if (*src)
+ if (errorCode) printf("Error code %d\n", errorCode);
+ else
{
- char txtInfo[64]; // Display at most first 64 characters of TXT record
- char *dst = txtInfo;
- const char *const lim = &txtInfo[sizeof(txtInfo)];
- while (*src && dst < lim-1)
- {
- if (*src == '\\') *dst++ = '\\'; // '\' displays as "\\"
- if (*src >= ' ') *dst++ = *src++; // Display normal characters as-is
- else
- {
- *dst++ = '\\'; // Display a backslash
- if (*src == 1) *dst++ = ' '; // String boundary displayed as "\ "
- else // Other chararacters displayed as "\0xHH"
- {
- static const char hexchars[16] = "0123456789ABCDEF";
- *dst++ = '0';
- *dst++ = 'x';
- *dst++ = hexchars[*src >> 4];
- *dst++ = hexchars[*src & 0xF];
- }
- src++;
- }
- }
- *dst++ = 0;
- printf(" TXT %s", txtInfo);
+ printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber);
+ if (flags) printf(" Flags: %X", flags);
+ // Don't show degenerate TXT records containing nothing but a single empty string
+ if (txtLen > 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); }
+ printf("\n");
}
- printf("\n");
- fflush( stdout );
+
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
static void myTimerCallBack(void)
{
printf("Adding big NULL record\n");
err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
+ if (err) printf("Failed: %d\n", err); else printf("Succeeded\n");
timeOut = LONG_TIME;
}
break;
if (err != kDNSServiceErr_NoError)
{
- fprintf(stderr, "DNSService call failed %ld\n", (long int)err);
+ fprintf(stderr, "DNSService add/update/remove failed %ld\n", (long int)err);
stopNow = 1;
}
}
-static void DNSSD_API reg_reply(DNSServiceRef client, DNSServiceFlags flags, DNSServiceErrorType errorCode,
+static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
const char *name, const char *regtype, const char *domain, void *context)
{
- (void)client; // Unused
+ (void)sdref; // Unused
(void)flags; // Unused
(void)context; // Unused
- printf("Got a reply for %s.%s%s: ", name, regtype, domain);
- switch (errorCode)
+ printtimestamp();
+ printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
+
+ if (errorCode == kDNSServiceErr_NoError)
{
- case kDNSServiceErr_NoError: printf("Name now registered and active\n"); break;
- case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1);
- default: printf("Error %d\n", errorCode); return;
+ if (flags & kDNSServiceFlagsAdd) printf("Name now registered and active\n");
+ else printf("Name registration removed\n");
+ if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5;
+ }
+ else if (errorCode == kDNSServiceErr_NameConflict)
+ {
+ printf("Name in use, please choose another\n");
+ exit(-1);
}
+ else
+ printf("Error %d\n", errorCode);
- if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5;
- fflush( stdout );
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
-static void DNSSD_API qr_reply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
+// Output the wire-format domainname pointed to by rd
+static int snprintd(char *p, int max, const unsigned char **rd)
+ {
+ const char *const buf = p;
+ const char *const end = p + max;
+ while (**rd) { p += snprintf(p, end-p, "%.*s.", **rd, *rd+1); *rd += 1 + **rd; }
+ *rd += 1; // Advance over the final zero byte
+ return(p-buf);
+ }
+
+static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
{
char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
const unsigned char *rd = rdata;
const unsigned char *end = (const unsigned char *) rdata + rdlen;
- char rdb[1000];
- char *p = rdb;
- const char * const lim = rdb + sizeof(rdb);
+ char rdb[1000] = "", *p = rdb;
+ int unknowntype = 0;
- (void)sdRef; // Unused
+ (void)sdref; // Unused
(void)flags; // Unused
(void)ifIndex; // Unused
- (void)errorCode;// Unused
(void)ttl; // Unused
(void)context; // Unused
- switch (rrtype)
+ if (num_printed++ == 0) printf("Timestamp A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
+ printtimestamp();
+
+ if (!errorCode)
{
- case kDNSServiceType_A: sprintf(rdb, "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]); break;
- default : p += snprintf(p, lim-p, "%d bytes%s", rdlen, rdlen ? ":" : "");
- while (rd < end && p < lim) p += snprintf(p, lim-p, " %02X", *rd++);
- break;
+ switch (rrtype)
+ {
+ case kDNSServiceType_A:
+ snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
+ break;
+
+ case kDNSServiceType_NS:
+ case kDNSServiceType_CNAME:
+ case kDNSServiceType_PTR:
+ case kDNSServiceType_DNAME:
+ p += snprintd(p, sizeof(rdb), &rd);
+ break;
+
+ case kDNSServiceType_SOA:
+ p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // mname
+ p += snprintf(p, rdb + sizeof(rdb) - p, " ");
+ p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // rname
+ p += snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d",
+ ntohl(((uint32_t*)rd)[0]), ntohl(((uint32_t*)rd)[1]), ntohl(((uint32_t*)rd)[2]), ntohl(((uint32_t*)rd)[3]), ntohl(((uint32_t*)rd)[4]));
+ break;
+
+ case kDNSServiceType_AAAA:
+ snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+ rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
+ rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
+ break;
+
+ case kDNSServiceType_SRV:
+ p += snprintf(p, rdb + sizeof(rdb) - p, "%d %d %d ", // priority, weight, port
+ ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4)));
+ rd += 6;
+ p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // target host
+ break;
+
+ default : snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : ""); unknowntype = 1; break;
+ }
}
- if (num_printed++ == 0) printf("Timestamp A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
+
+ printf("%s%6X%3d %-30s%4d%4d %s", op, flags, ifIndex, fullname, rrtype, rrclass, rdb);
+ if (unknowntype) while (rd < end) printf(" %02X", *rd++);
+ if (errorCode)
+ {
+ if (errorCode == kDNSServiceErr_NoSuchRecord) printf("No Such Record");
+ else printf("Error code %d", errorCode);
+ }
+ printf("\n");
+
+ if (operation == 'C')
+ if (flags & kDNSServiceFlagsAdd)
+ DNSServiceReconfirmRecord(flags, ifIndex, fullname, rrtype, rrclass, rdlen, rdata);
+
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+ }
+
+#if HAS_NAT_PMP_API
+static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, uint32_t publicAddress, uint32_t protocol, uint16_t privatePort, uint16_t publicPort, uint32_t ttl, void *context)
+ {
+ (void)sdref; // Unused
+ (void)context; // Unused
+ (void)flags; // Unused
+
+ if (num_printed++ == 0) printf("Timestamp if %-20s %-15s %-15s %-15s %s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL");
+ printtimestamp();
+ if (errorCode) printf("Error code %d\n", errorCode);
+ else
+ {
+ const unsigned char *digits = (const unsigned char *)&publicAddress;
+ char addr[256];
+
+ snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
+ printf("%-4d %-20s %-15d %-15d %-15d %d\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl);
+ }
+ fflush(stdout);
+ }
+#endif
+
+#if HAS_ADDRINFO_API
+static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context)
+ {
+ char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
+ char addr[256] = "";
+ (void) sdref;
+ (void) context;
+
+ if (num_printed++ == 0) printf("Timestamp A/R Flags if %-25s %-40s %s\n", "Hostname", "Address", "TTL");
printtimestamp();
- printf("%s%6X%3d %-30s%4d%4d %s\n", op, flags, ifIndex, fullname, rrtype, rrclass, rdb);
- fflush( stdout );
+
+ if (address && address->sa_family == AF_INET)
+ {
+ const unsigned char *digits = (const unsigned char *) &((struct sockaddr_in *)address)->sin_addr;
+ snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
+ }
+ else if (address && address->sa_family == AF_INET6)
+ {
+ const unsigned char *digits = (const unsigned char *) &((struct sockaddr_in6 *)address)->sin6_addr;
+ snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+ digits[0x0], digits[0x1], digits[0x2], digits[0x3], digits[0x4], digits[0x5], digits[0x6], digits[0x7],
+ digits[0x8], digits[0x9], digits[0xA], digits[0xB], digits[0xC], digits[0xD], digits[0xE], digits[0xF]);
+ }
+
+ printf("%s%6X%3d %-25s %-40s %d", op, flags, interfaceIndex, hostname, addr, ttl);
+ if (errorCode)
+ {
+ if (errorCode == kDNSServiceErr_NoSuchRecord) printf(" No Such Record");
+ else printf(" Error code %d", errorCode);
+ }
+ printf("\n");
+
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
+#endif
//*************************************************************************************************************
// The main test function
static void HandleEvents(void)
{
- int dns_sd_fd = client ? DNSServiceRefSockFD(client ) : -1;
- int dns_sd_fd2 = client2 ? DNSServiceRefSockFD(client2) : -1;
+ int dns_sd_fd = client ? DNSServiceRefSockFD(client ) : -1;
+ int dns_sd_fd2 = client_pa ? DNSServiceRefSockFD(client_pa) : -1;
int nfds = dns_sd_fd + 1;
fd_set readfds;
struct timeval tv;
FD_ZERO(&readfds);
// 2. Add the fd for our client(s) to the fd_set
- if (client ) FD_SET(dns_sd_fd , &readfds);
- if (client2) FD_SET(dns_sd_fd2, &readfds);
+ if (client ) FD_SET(dns_sd_fd , &readfds);
+ if (client_pa) FD_SET(dns_sd_fd2, &readfds);
// 3. Set up the timeout.
- tv.tv_sec = timeOut;
+ tv.tv_sec = timeOut;
tv.tv_usec = 0;
result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
if (result > 0)
{
DNSServiceErrorType err = kDNSServiceErr_NoError;
- if (client && FD_ISSET(dns_sd_fd , &readfds)) err = DNSServiceProcessResult(client );
- else if (client2 && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client2);
+ if (client && FD_ISSET(dns_sd_fd , &readfds)) err = DNSServiceProcessResult(client );
+ else if (client_pa && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client_pa);
if (err) { fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; }
}
else if (result == 0)
}
}
-static int getfirstoption( int argc, char **argv, const char *optstr, int *pOptInd)
+static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd)
// Return the recognized option in optstr and the option index of the next arg.
#if NOT_HAVE_GETOPT
{
- int i;
- for ( i=1; i < argc; i++)
+ int i;
+ for (i=1; i < argc; i++)
{
- if ( argv[i][0] == '-' && &argv[i][1] &&
- NULL != strchr( optstr, argv[i][1]))
+ if (argv[i][0] == '-' && &argv[i][1] &&
+ NULL != strchr(optstr, argv[i][1]))
{
*pOptInd = i + 1;
return argv[i][1];
}
#else
{
- int operation = getopt(argc, (char * const *)argv, optstr);
+ int operation = getopt(argc, (char *const *)argv, optstr);
*pOptInd = optind;
return operation;
}
#endif
-static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, DNSServiceFlags flags,
- DNSServiceErrorType errorCode, void * context)
+static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, const DNSServiceFlags flags,
+ DNSServiceErrorType errorCode, void *context)
{
char *name = (char *)context;
(void)record; // Unused
(void)flags; // Unused
- printf("Got a reply for %s: ", name);
+ printtimestamp();
+ printf("Got a reply for record %s: ", name);
+
switch (errorCode)
{
case kDNSServiceErr_NoError: printf("Name now registered and active\n"); break;
case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1);
- default: printf("Error %d\n", errorCode); return;
+ default: printf("Error %d\n", errorCode); break;
+ }
+ if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+ // DNSServiceRemoveRecord(service, record, 0); to test record removal
+ }
+
+static unsigned long getip(const char *const name)
+ {
+ unsigned long ip = 0;
+ struct addrinfo hints;
+ struct addrinfo *addrs = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+
+ if (getaddrinfo(name, NULL, &hints, &addrs) == 0)
+ {
+ ip = ((struct sockaddr_in*) addrs->ai_addr)->sin_addr.s_addr;
+ }
+
+ if (addrs)
+ {
+ freeaddrinfo(addrs);
}
- fflush( stdout );
+
+ return(ip);
}
-static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef *sdRef, const char *host, const char *ip)
+static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip)
{
- unsigned long addr = inet_addr(ip);
- DNSServiceErrorType err = DNSServiceCreateConnection(sdRef);
- if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
- return(DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, kDNSServiceInterfaceIndexAny, host,
+ // Call getip() after the call DNSServiceCreateConnection().
+ // On the Win32 platform, WinSock must be initialized for getip() to succeed.
+ // Any DNSService* call will initialize WinSock for us, so we make sure
+ // DNSServiceCreateConnection() is called before getip() is.
+ unsigned long addr = getip(ip);
+ return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
kDNSServiceType_A, kDNSServiceClass_IN, sizeof(addr), &addr, 240, MyRegisterRecordCallback, (void*)host));
+ // Note, should probably add support for creating proxy AAAA records too, one day
}
-static DNSServiceErrorType RegisterService(DNSServiceRef *sdRef,
+#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
+ ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \
+ ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : 0)
+
+#define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1]))
+
+static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv)
{
+ DNSServiceFlags flags = 0;
uint16_t PortAsNumber = atoi(port);
Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
unsigned char txt[2048] = "";
if (nam[0] == '.' && nam[1] == 0) nam = ""; // We allow '.' on the command line as a synonym for empty string
if (dom[0] == '.' && dom[1] == 0) dom = ""; // We allow '.' on the command line as a synonym for empty string
- for (i = 0; i < argc; i++)
+ printf("Registering Service %s.%s%s%s", nam[0] ? nam : "<<Default>>", typ, dom[0] ? "." : "", dom);
+ if (host && *host) printf(" host %s", host);
+ printf(" port %s", port);
+
+ if (argc)
{
- unsigned char *len = ptr++;
- *len = strlen(argv[i]);
- strcpy((char*)ptr, argv[i]);
- ptr += *len;
+ for (i = 0; i < argc; i++)
+ {
+ const char *p = argv[i];
+ *ptr = 0;
+ while (*p && *ptr < 255 && ptr + 1 + *ptr < txt+sizeof(txt))
+ {
+ if (p[0] != '\\' || p[1] == 0) { ptr[++*ptr] = *p; p+=1; }
+ else if (p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3])) { ptr[++*ptr] = HexPair(p+2); p+=4; }
+ else { ptr[++*ptr] = p[1]; p+=2; }
+ }
+ ptr += 1 + *ptr;
+ }
+ printf(" TXT");
+ ShowTXTRecord(ptr-txt, txt);
}
+ printf("\n");
- printf("Registering Service %s.%s%s", nam, typ, dom);
- if (host && *host) printf(" host %s", host);
- printf(" port %s %s\n", port, txt);
- return(DNSServiceRegister(sdRef, /* kDNSServiceFlagsAllowRemoteQuery */ 0, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, ptr-txt, txt, reg_reply, NULL));
+ //flags |= kDNSServiceFlagsAllowRemoteQuery;
+ //flags |= kDNSServiceFlagsNoAutoRename;
+
+ return(DNSServiceRegister(sdref, flags, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, (uint16_t) (ptr-txt), txt, reg_reply, NULL));
}
int main(int argc, char **argv)
{
-#ifdef _WIN32
- const char kFilePathSep = '\\';
-#else
- const char kFilePathSep = '/';
-#endif
DNSServiceErrorType err;
char *dom;
- int optind;
- const char *progname = strrchr(argv[0], kFilePathSep) ? strrchr(argv[0], kFilePathSep) + 1 : argv[0];
-#ifndef NOT_HAVE_SETLINEBUF
- setlinebuf(stdout); // Want to see lines as they appear, not block buffered
-#endif
+ int optind;
+
+ // Extract the program name from argv[0], which by convention contains the path to this executable.
+ // Note that this is just a voluntary convention, not enforced by the kernel --
+ // the process calling exec() can pass bogus data in argv[0] if it chooses to.
+ const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
+ if (a0 == (const char *)1) a0 = argv[0];
+
+ if (sizeof(argv) == 8) printf("Running in 64-bit mode\n");
+
+ // Test code for TXTRecord functions
+ //TXTRecordRef txtRecord;
+ //TXTRecordCreate(&txtRecord, 0, NULL);
+ //TXTRecordSetValue(&txtRecord, "aaa", 1, "b");
+ //printf("%d\n", TXTRecordContainsKey(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), "Aaa"));
if (argc > 1 && !strcmp(argv[1], "-lo"))
{
printf("Using LocalOnly\n");
}
+ if (argc > 2 && !strcmp(argv[1], "-i"))
+ {
+ opinterface = if_nametoindex(argv[2]);
+ if (!opinterface) opinterface = atoi(argv[2]);
+ if (!opinterface) { fprintf(stderr, "Unknown interface %s\n", argv[2]); goto Fail; }
+ argc -= 2;
+ argv += 2;
+ }
+
if (argc < 2) goto Fail; // Minimum command line is the command name and one argument
- operation = getfirstoption( argc, argv, "EFBLQRPAUNTMI", &optind);
+ operation = getfirstoption(argc, argv, "EFBLRPQCAUNTMISV"
+ #if HAS_NAT_PMP_API
+ "X"
+ #endif
+ #if HAS_ADDRINFO_API
+ "G"
+ #endif
+ , &optind);
if (operation == -1) goto Fail;
+ if (opinterface) printf("Using interface %d\n", opinterface);
+
switch (operation)
{
case 'E': printf("Looking for recommended registration domains:\n");
//enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "dns-sd.ibm.com.", NULL);
break;
- case 'B': if (argc < optind+1) goto Fail;
- dom = (argc < optind+2) ? "" : argv[optind+1];
+ case 'B': {
+ char buffer[64], *typ;
+ typ = (argc < optind+1) ? "_http" : argv[optind+0]; // If no type argument, browse for advertised web pages
+ dom = (argc < optind+2) ? "" : argv[optind+1]; // Missing domain argument is the same as empty string i.e. use system default(s)
if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
- printf("Browsing for %s%s\n", argv[optind+0], dom);
- err = DNSServiceBrowse(&client, 0, opinterface, argv[optind+0], dom, browse_reply, NULL);
+ if (!strchr(typ, '.')) { snprintf(buffer, sizeof(buffer), "%s._tcp", typ); typ = buffer; }
+ printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
+ err = DNSServiceBrowse(&client, 0, opinterface, typ, dom, browse_reply, NULL);
break;
+ }
case 'L': if (argc < optind+2) goto Fail;
dom = (argc < optind+3) ? "local" : argv[optind+2];
if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local"
printf("Lookup %s.%s.%s\n", argv[optind+0], argv[optind+1], dom);
- err = DNSServiceResolve(&client, 0, opinterface, argv[optind+0], argv[optind+1], dom, resolve_reply, NULL);
+ err = DNSServiceResolve(&client, 0, opinterface, argv[optind+0], argv[optind+1], dom, (DNSServiceResolveReply)resolve_reply, NULL);
break;
case 'R': if (argc < optind+4) goto Fail;
break;
case 'P': if (argc < optind+6) goto Fail;
- err = RegisterProxyAddressRecord(&client2, argv[optind+4], argv[optind+5]);
+ err = DNSServiceCreateConnection(&client_pa);
+ if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
+ err = RegisterProxyAddressRecord(client_pa, argv[optind+4], argv[optind+5]);
+ //err = RegisterProxyAddressRecord(client_pa, "two", argv[optind+5]);
if (err) break;
err = RegisterService(&client, argv[optind+0], argv[optind+1], argv[optind+2], argv[optind+4], argv[optind+3], argc-(optind+6), argv+(optind+6));
+ //DNSServiceRemoveRecord(client_pa, record, 0);
+ //DNSServiceRemoveRecord(client_pa, record, 0);
break;
- case 'Q': {
+ case 'Q':
+ case 'C': {
uint16_t rrtype, rrclass;
- DNSServiceFlags flags = 0;
+ DNSServiceFlags flags = kDNSServiceFlagsReturnIntermediates;
if (argc < optind+1) goto Fail;
rrtype = (argc <= optind+1) ? kDNSServiceType_A : GetRRType(argv[optind+1]);
rrclass = (argc <= optind+2) ? kDNSServiceClass_IN : atoi(argv[optind+2]);
break;
}
+#if HAS_NAT_PMP_API
+ case 'X': {
+ if (argc == optind) // If no arguments, just fetch IP address
+ err = DNSServiceNATPortMappingCreate(&client, 0, 0, 0, 0, 0, 0, port_mapping_create_reply, NULL);
+ else if (argc >= optind+2 && atoi(argv[optind+0]) == 0)
+ {
+ DNSServiceProtocol prot = GetProtocol(argv[optind+0]); // Must specify TCP or UDP
+ uint16_t IntPortAsNumber = atoi(argv[optind+1]); // Must specify internal port
+ uint16_t ExtPortAsNumber = (argc < optind+3) ? 0 : atoi(argv[optind+2]); // Optional desired external port
+ uint32_t ttl = (argc < optind+4) ? 0 : atoi(argv[optind+3]); // Optional desired lease lifetime
+ Opaque16 intp = { { IntPortAsNumber >> 8, IntPortAsNumber & 0xFF } };
+ Opaque16 extp = { { ExtPortAsNumber >> 8, ExtPortAsNumber & 0xFF } };
+ err = DNSServiceNATPortMappingCreate(&client, 0, 0, prot, intp.NotAnInteger, extp.NotAnInteger, ttl, port_mapping_create_reply, NULL);
+ }
+ else goto Fail;
+ break;
+ }
+#endif
+
+#if HAS_ADDRINFO_API
+ case 'G': {
+ if (argc != optind+2) goto Fail;
+ else err = DNSServiceGetAddrInfo(&client, kDNSServiceFlagsReturnIntermediates, opinterface, GetProtocol(argv[optind+0]), argv[optind+1], addrinfo_reply, NULL);
+ break;
+ }
+#endif
+
+ case 'S': {
+ Opaque16 registerPort = { { 0x23, 0x45 } };
+ err = DNSServiceCreateConnection(&client);
+ if (err) { fprintf(stderr, "DNSServiceCreateConnection failed %ld\n", (long int)err); return (-1); }
+
+ sc1 = client;
+ err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, "_http._tcp", "", browse_reply, NULL);
+ if (err) { fprintf(stderr, "DNSServiceBrowse _http._tcp failed %ld\n", (long int)err); return (-1); }
+
+ sc2 = client;
+ err = DNSServiceBrowse(&sc2, kDNSServiceFlagsShareConnection, opinterface, "_ftp._tcp", "", browse_reply, NULL);
+ if (err) { fprintf(stderr, "DNSServiceBrowse _ftp._tcp failed %ld\n", (long int)err); return (-1); }
+
+ sc3 = client;
+ err = DNSServiceRegister(&sc3, kDNSServiceFlagsShareConnection, opinterface, "kDNSServiceFlagsShareConnection",
+ "_http._tcp", "local", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
+ if (err) { fprintf(stderr, "SharedConnection DNSServiceRegister failed %ld\n", (long int)err); return (-1); }
+
+ break;
+ }
+
+ case 'V': {
+ uint32_t v;
+ uint32_t size = sizeof(v);
+ err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &v, &size);
+ if (err) fprintf(stderr, "DNSServiceGetProperty failed %ld\n", (long int)err);
+ else printf("Currently running daemon (system service) is version %d.%d\n", v / 10000, v / 100 % 100);
+ exit(0);
+ }
+
default: goto Fail;
}
HandleEvents();
// Be sure to deallocate the DNSServiceRef when you're finished
- if (client ) DNSServiceRefDeallocate(client );
- if (client2) DNSServiceRefDeallocate(client2);
+ if (client ) DNSServiceRefDeallocate(client );
+ if (client_pa) DNSServiceRefDeallocate(client_pa);
return 0;
Fail:
- fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", progname);
- fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", progname);
- fprintf(stderr, "%s -B <Type> <Domain> (Browse for services instances)\n", progname);
- fprintf(stderr, "%s -L <Name> <Type> <Domain> (Look up a service instance)\n", progname);
- fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", progname);
- fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Proxy)\n", progname);
- fprintf(stderr, "%s -Q <FQDN> <rrtype> <rrclass> (Generic query for any record type)\n", progname);
- fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", progname);
- fprintf(stderr, "%s -U (Test updating a TXT record)\n", progname);
- fprintf(stderr, "%s -N (Test adding a large NULL record)\n", progname);
- fprintf(stderr, "%s -T (Test creating a large TXT record)\n", progname);
- fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", progname);
- fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", progname);
+ fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", a0);
+ fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", a0);
+ fprintf(stderr, "%s -B <Type> <Domain> (Browse for services instances)\n", a0);
+ fprintf(stderr, "%s -L <Name> <Type> <Domain> (Look up a service instance)\n", a0);
+ fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", a0);
+ fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Proxy)\n", a0);
+ fprintf(stderr, "%s -Q <FQDN> <rrtype> <rrclass> (Generic query for any record type)\n", a0);
+ fprintf(stderr, "%s -C <FQDN> <rrtype> <rrclass> (Query; reconfirming each result)\n", a0);
+#if HAS_NAT_PMP_API
+ fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL> (NAT Port Mapping)\n", a0);
+#endif
+#if HAS_ADDRINFO_API
+ fprintf(stderr, "%s -G v4/v6/v4v6 <Hostname> (Get address information for hostname)\n", a0);
+#endif
+ fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", a0);
+ fprintf(stderr, "%s -U (Test updating a TXT record)\n", a0);
+ fprintf(stderr, "%s -N (Test adding a large NULL record)\n", a0);
+ fprintf(stderr, "%s -T (Test creating a large TXT record)\n", a0);
+ fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", a0);
+ fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", a0);
+ fprintf(stderr, "%s -S (Test multiple operations on a shared socket)\n", a0);
+ fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", a0);
return 0;
}
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
--- /dev/null
+The majority of the source code in the mDNSResponder project is licensed
+under the terms of the Apache License, Version 2.0, available from:
+ <http://www.apache.org/licenses/LICENSE-2.0>
+
+To accommodate license compatibility with the widest possible range
+of client code licenses, the shared library code, which is linked
+at runtime into the same address space as the client using it, is
+licensed under the terms of the "Three-Clause BSD License".
+
+The Linux Name Service Switch code, contributed by National ICT
+Australia Ltd (NICTA) is licensed under the terms of the NICTA Public
+Software Licence (which is substantially similar to the "Three-Clause
+BSD License", with some additional language pertaining to Australian law).
include /Developer/Makefiles/pb_makefiles/platform.make
-MVERS = "mDNSResponder-108.6"
+MVERS = "mDNSResponder-161.1"
+
+DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
+
+installSome:
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some
+
+SystemLibraries:
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries
install:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT)
+ # Make sure ddnswriteconfig is owned by root:wheel, then make it setuid root executable
+ if test -e $(DDNSWRITECONFIG) ; then chown 0:80 $(DDNSWRITECONFIG) ; chmod 4555 $(DDNSWRITECONFIG) ; fi
installsrc:
- ditto . ${SRCROOT}
+ ditto . "$(SRCROOT)"
installhdrs::
cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
--- /dev/null
+Private DNS
+
+Summary
+
+Private DNS is an extension to standard Wide Area Bonjour that allows
+for secure, encrypted, and authorized communications. Private data sent
+from a client to a DNS server is encrypted using Transport Layer
+Security (TLS), ensuring that the data is hidden from prying eyes, and
+contains Transaction Signatures (TSIG), so the server can authorize the
+request. TSIGs are typically associated with Dynamic Updates; we are
+using them for standard and long-lived queries as well. Private DNS also
+protects Dynamic Updates from eavesdropping, by wrapping the update in a
+TLS communication channel if the server has been configured appropriately.
+
+Architectural Overview
+
+mDNSResponder has been modified to automatically issue a private query
+when necessary. After receiving an NXDOMAIN error, mDNSResponder checks
+in the system keychain to see if the user has a DNS query key (TSIG key)
+for the name in question, or for a parent of that name. If a suitable
+key is found, mDNSResponder looks up the zone data associated with the
+name of the question. After determining the correct name server,
+mDNSResponder looks up an additional SRV record "_dns-private._tcp". If
+it finds this record, mDNSResponder will re-issue the query privately.
+If either there is no _dns-private._tcp record, or there is no secret
+key, the call fails as it initially did, with an NXDOMAIN error.
+
+Once the secret key is found and the SRV record is looked up, mDNSResponder
+opens a TLS connection to the server on the port specified in the SRV
+record just looked up. After the connection succeeds, mDNSResponder
+can proceed to use that communication channel to make requests of
+the server. Every private packet must also have a TSIG record;
+the DNS server uses this TSIG record to allow access to its data.
+
+When setting up a long-lived query over TCP (with or without TLS)
+TCP's standard three-way handshake makes the full four-packet LLQ setup
+exchange described in <http://files.dns-sd.org/draft-sekar-dns-llq.txt>
+unnecessary. Instead, when connecting over TCP, the client simply sends
+a setup message and expects to receive ACK + Answers. The setup message
+sent is formatted as described in the LLQ document, however there is
+an additional TSIG' resource record added to the end of it. The TSIG
+resource records looks and acts exactly as it does in a secure update.
+So when the server receives an LLQ (or a standard query), it looks to
+see if the zone that is being referenced is public or private. If it's
+private, then it makes sure that the client is authorized to query that
+zone (by using the TSIG signature) and returns the appropriate data.
+When a zone is configured as private, the server will do this type of
+authorization checking for every query except those queries that are
+looking for SOA and NS records.
+
+Implementation Issues
+
+dnsextd
+
+dnsextd has been modified to behave much like a DNS firewall. The "real"
+DNS server is configured to listen on non-standard ports on the loopback
+interface. dnsextd then listens on the standard DNS ports (TCP/UDP port
+53) and intercepts all DNS traffic. It is responsible for determining
+what zone a DNS request is associated with, determining whether the
+client is allowed access to that zone, and returning the appropriate
+information back to the caller. If the packet is allowed access, dnsextd
+forwards the request to the "real" nameserver, and returns the result to
+the caller.
+
+It was tempting to use BIND9's facility for configuring TSIG enabled
+queries while doing this work. However after proceeding down that path,
+enough subtle interaction problems were found that it was not practical
+to pursue this direction, so instead dnsextd does all TSIG processing
+for queries itself. It does continue to use BIND9 for processing TSIG
+enabled dynamic updates, though one minor downside with this is that
+there are two configuration files (named.conf or dnsextd.conf) that have
+the same secret key information. That seems redundant and error-prone,
+and moving all TSIG processing for both queries and updates into dnsextd
+would fix this.
+
+All private LLQ operations are TSIG-enabled and sent over a secure
+encrypted TLS channel. To accommodate service providers who don't want
+to have to keep open a large number of TLS connections to a large number
+of client machines, the server has the option of dropping the TSL
+connection after initial LLQ setup and sending subsequent events and
+refreshes using unencrypted UDP packets. This results in less load on
+the server, at the cost of slightly lower security (LLQs can only be set
+up by an authorized client, but once set up, subsequent change event
+packets sent over unencrypted UDP could be observed by an eavesdropper).
+A potential solution to this deficiency might be in using DTLS, which is
+a protocol based on TLS that is capable of securing datagram traffic.
+More investigation needs to be done to see if DTLS is suitable for
+private DNS.
+
+It was necessary to relax one of the checks that dnsextd performs during
+processing of an LLQ refresh. Prior to these changes, dnsextd would
+verify that the refresh request came from the same entity that setup the
+LLQ by comparing both the IP Address and port number of the request
+packet with the IP Address and port number of the setup packet. Because
+of the preceding issue, a refresh request might be sent over two
+different sockets. While their IP addresses would be the same, their
+port numbers could potentially differ. This check has been modified to
+only check that the IP addresses match.
+
+When setting up a semi-private LLQ (where the request and initial answer
+set is sent over TLS/TCP, but subsequent change events are sent over
+unencrypted UDP), dnsextd uses the port number of the client's TCP
+socket to determine the UDP event port number. While this eliminates the
+need to pass the UDP event port number in the LLQ setup request
+(obviating a potential data mismatch error), I think it does more harm
+than good, for three reasons:
+
+1) We are relying that all the routers out there implement the Port
+ Mapping Protocol spec correctly.
+
+2) Upon setup every LLQ must NAT map two ports. Upon tear down every LLQ
+ must tear down two NAT mappings.
+
+3) Every LLQ opens up two sockets (TCP and UDP), rather than just the
+ one TCP socket.
+
+All of this just to avoid sending two bytes in the LLQ setup packet
+doesn't seem logical. The approach also necessitates creating an
+additional UDP socket for every private LLQ, port mapping both the TCP
+socket as well as the UDP socket, and moderately increasing the
+complexity and efficiency of the code. Because of this we plan to allow
+the LLQ setup packet to specify a different UDP port for change event
+packets. This will allow mDNSResponder to receive all UDP change event
+packets on a single UDP port, instead of a different one for each LLQ.
+
+Currently, dnsextd is buggy on multi-homed hosts. If it receives a
+packet on interface 2, it will reply on interface 1 causing an error in
+the client program.
+
+dnsextd doesn't fully process all of its option parameters.
+Specifically, it doesn't process the keywords: "listen-on",
+"nameserver", "private", and "llq". It defaults to expecting the "real"
+nameserver to be listening on 127.0.0.1:5030.
+
+
+mDNSResponder
+
+Currently, mDNSResponder attempts to issue private queries for all
+queries that initially result in an NXDOMAIN error. This behavior might
+be modified in future versions, however it seems patently incorrect to
+do this for reverse name lookups. The code that attempts to get the zone
+data associated with the name will never find the zone for a reverse
+name lookup, and so will issue a number of wasteful DNS queries.
+
+mDNSResponder doesn't handle SERV_FULL or STATIC return codes after
+setting up an LLQ over TCP. This isn't a terrible problem right now,
+because dnsextd doesn't ever return them, but this should be fixed so
+that mDNSResponder will work when talking to other servers that do
+return these error codes.
+
+
+Configuration:
+
+Sample named.conf:
+
+//
+// Include keys file
+//
+include "/etc/rndc.key";
+// Declares control channels to be used by the rndc utility.
+//
+// It is recommended that 127.0.0.1 be the only address used.
+// This also allows non-privileged users on the local host to manage
+// your name server.
+
+//
+// Default controls
+//
+controls
+ {
+ inet 127.0.0.1 port 54 allow { any; } keys { "rndc-key"; };
+ };
+
+options
+ {
+ directory "/var/named";
+ /*
+ * If there is a firewall between you and nameservers you want
+ * to talk to, you might need to uncomment the query-source
+ * directive below. Previous versions of BIND always asked
+ * questions using port 53, but BIND 8.1 uses an unprivileged
+ * port by default.
+ */
+
+ forwarders
+ {
+ 65.23.128.2;
+ 65.23.128.3;
+ };
+
+ listen-on port 5030 { 127.0.0.1; };
+ recursion true;
+ };
+
+//
+// a caching only nameserver config
+//
+zone "." IN
+ {
+ type hint;
+ file "named.ca";
+ };
+
+zone "localhost" IN
+ {
+ type master;
+ file "localhost.zone";
+ allow-update { none; };
+ };
+
+zone "0.0.127.in-addr.arpa" IN
+ {
+ type master;
+ file "named.local";
+ allow-update { none; };
+ };
+
+zone "hungrywolf.org." in
+ {
+ type master;
+ file "db.hungrywolf.org";
+ allow-update { key hungrywolf.org.; };
+ };
+
+zone "157.23.65.in-addr.arpa" IN
+ {
+ file "db.65.23.157";
+ type master;
+ };
+
+zone "100.255.17.in-addr.arpa" IN
+ {
+ file "db.17.255.100";
+ type master;
+ };
+
+zone "66.6.24.in-addr.arpa" IN
+ {
+ file "db.24.6.66";
+ type master;
+ };
+
+key hungrywolf.org.
+ {
+ algorithm hmac-md5;
+ secret "c8LWr16K6ju6KMO5zT6Tyg==";
+ };
+
+logging
+ {
+ category default { _default_log; };
+
+ channel _default_log
+ {
+ file "/Library/Logs/named.log";
+ severity info;
+ print-time yes;
+ };
+ };
+
+
+Sample dnsextd.conf:
+
+options { };
+
+key "hungrywolf.org."
+ {
+ secret "c8LWr16K6ju6KMO5zT6Tyg==";
+ };
+
+zone "hungrywolf.org."
+ {
+ type private;
+ allow-query { key hungrywolf.org.; };
+ };
*
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSCommon.c,v $
-Revision 1.96.2.1 2006/10/31 02:50:16 cheshire
-<rdar://problem/4683163> mDNSResponder insufficiently defensive against malformed browsing PTR responses
+Revision 1.184 2007/10/05 17:56:07 cheshire
+Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
-Revision 1.96 2006/03/10 21:51:42 cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Split out SameRDataBody() into a separate routine so it can be called from other code
+Revision 1.183 2007/10/02 18:33:46 cheshire
+Improved GetRRDisplayString to show all constituent strings within a text record
+(up to the usual MaxMsg 120-character limit)
-Revision 1.95 2006/03/08 22:43:11 cheshire
-Use "localdomain" symbol instead of literal string
+Revision 1.182 2007/10/01 19:45:01 cheshire
+<rdar://problem/5514859> BTMM: Sometimes Back to My Mac autotunnel registrations are malformed
-Revision 1.94 2006/03/02 21:59:55 cheshire
-<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
-Improve sanity checks & debugging support in GetLargeResourceRecord()
+Revision 1.181 2007/10/01 18:36:53 cheshire
+Yet another fix to finally get the DumpPacket RCODE display right
-Revision 1.93 2006/03/02 20:30:47 cheshire
-Improved GetRRDisplayString to also show priority, weight, and port for SRV records
-
-Revision 1.92 2005/09/16 21:06:49 cheshire
-Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
-
-Revision 1.91 2005/07/10 22:10:37 cheshire
-The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to
-hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that
-large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires.
+Revision 1.180 2007/09/29 21:30:38 cheshire
+In DumpPacket/DumpRecords, show an error line if we run out of packet data
-Revision 1.90 2005/03/21 00:33:51 shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
+Revision 1.179 2007/09/29 20:44:56 cheshire
+Fix error in DumpPacket where it was not displaying the RCODE field properly
-Revision 1.89 2005/03/17 18:59:38 ksekar
-<rdar://problem/4012279> Properly parse multiple LLQ Options per packet on Windows
+Revision 1.178 2007/09/27 21:11:44 cheshire
+Fixed spelling mistake: ROCDE -> RCODE
-Revision 1.88 2005/03/16 00:42:32 ksekar
-<rdar://problem/4012279> Long-lived queries not working on Windows
+Revision 1.177 2007/09/27 18:51:26 cheshire
+Improved DumpPacket to use "Zone/Prerequisites/Updates" nomenclature when displaying a DNS Update packet
-Revision 1.87 2005/02/25 04:21:00 cheshire
-<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
+Revision 1.176 2007/09/27 17:53:37 cheshire
+Add display of RCODE and flags in DumpPacket output
-Revision 1.86 2005/02/18 00:43:12 cheshire
-<rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
+Revision 1.175 2007/09/26 22:26:40 cheshire
+Also show DNS query/response ID in DumpPacket output
-Revision 1.85 2005/02/10 22:35:17 cheshire
-<rdar://problem/3727944> Update name
+Revision 1.174 2007/09/26 16:36:02 cheshire
+In DumpPacket output, begin header line with "-- " to make it visually stand out better
-Revision 1.84 2005/02/03 00:44:38 cheshire
-<rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
+Revision 1.173 2007/09/26 00:49:46 cheshire
+Improve packet logging to show sent and received packets,
+transport protocol (UDP/TCP/TLS) and source/destination address:port
-Revision 1.83 2005/01/27 22:57:55 cheshire
-Fix compile errors on gcc4
+Revision 1.172 2007/09/21 23:14:39 cheshire
+<rdar://problem/5498009> BTMM: Need to log updates and query packet contents in verbose debug mode
+Changed DumpRecords to use LargeCacheRecord on the stack instead of the shared m->rec storage,
+to eliminate "GetLargeResourceRecord: m->rec appears to be already in use" warnings
-Revision 1.82 2005/01/19 03:27:03 cheshire
-<rdar://problem/3961051> CPU Spin in mDNSResponder
-GetNextScheduledEvent() needs to check LocalRecordReady()
+Revision 1.171 2007/09/21 21:12:36 cheshire
+<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
-Revision 1.81 2004/12/18 03:13:45 cheshire
-<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
+Revision 1.170 2007/09/07 21:16:58 cheshire
+Add new symbol "NATPMPAnnouncementPort" (5350)
-Revision 1.80 2004/12/16 21:46:43 cheshire
-Add DNSTypeName case for kDNSType_SOA
+Revision 1.169 2007/08/30 00:31:20 cheshire
+Improve "locking failure" debugging messages to show function name using __func__ macro
-Revision 1.79 2004/12/16 21:38:37 cheshire
-Add DNSTypeName case for kDNSType_NS
+Revision 1.168 2007/08/28 23:58:42 cheshire
+Rename HostTarget -> AutoTarget
-Revision 1.78 2004/12/16 21:27:37 ksekar
-Fixed build failures when compiled with verbose debugging messages
+Revision 1.167 2007/08/10 23:10:05 vazquez
+<rdar://problem/5389850> mDNS: Reverse lookups of IPv6 link-local addresses always fail
-Revision 1.77 2004/12/16 20:12:59 cheshire
-<rdar://problem/3324626> Cache memory management improvements
+Revision 1.166 2007/08/01 16:09:13 cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-Revision 1.76 2004/12/16 08:05:29 shersche
-Remove extranenous semicolons that cause compilation errors on Windows
+Revision 1.165 2007/08/01 00:04:13 cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
-Revision 1.75 2004/12/15 02:11:22 ksekar
-<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
+Revision 1.164 2007/07/27 20:48:43 cheshire
+In DumpRecords(), include record TTL in output
-Revision 1.74 2004/12/09 22:49:15 ksekar
-<rdar://problem/3913653> Wide-Area Goodbyes broken
+Revision 1.163 2007/07/16 20:10:11 vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
+Added SSDP port number
-Revision 1.73 2004/12/07 22:49:06 cheshire
-<rdar://problem/3908850> BIND doesn't allow zero-length TXT records
+Revision 1.162 2007/07/10 01:59:33 cheshire
+<rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
+Fixed GetPktLease to use shared m->rec instead of putting LargeCacheRecord on the stack
-Revision 1.72 2004/12/06 21:15:20 ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+Revision 1.161 2007/07/06 18:56:26 cheshire
+Check m->NextScheduledNATOp in GetNextScheduledEvent()
-Revision 1.71 2004/12/04 02:12:45 cheshire
-<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
+Revision 1.160 2007/06/29 00:06:42 vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-Revision 1.70 2004/12/03 19:52:44 ksekar
-Use PutResourceRecordTTLJumbo for putDeletionRecord()
+Revision 1.159 2007/06/28 21:17:17 cheshire
+Rename "m->nextevent" as more informative "m->NextuDNSEvent"
-Revision 1.69 2004/12/03 07:20:50 ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
+Revision 1.158 2007/05/25 00:25:43 cheshire
+<rdar://problem/5227737> Need to enhance putRData to output all current known types
-Revision 1.68 2004/11/24 00:10:43 cheshire
-<rdar://problem/3869241> For unicast operations, verify that service types are legal
+Revision 1.157 2007/05/23 00:32:15 cheshire
+Don't treat uDNS responses as an entire RRSet (kDNSRecordTypePacketUniqueMask)
+when received in a truncated UDP response
-Revision 1.67 2004/10/26 03:52:02 cheshire
-Update checkin comments
+Revision 1.156 2007/05/15 00:29:00 cheshire
+Print «ZERO ADDRESS» for %#a with a zero mDNSAddr
-Revision 1.66 2004/10/23 01:16:00 cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+Revision 1.155 2007/05/07 22:07:47 cheshire
+<rdar://problem/4738025> Enhance GetLargeResourceRecord to decompress more record types
-Revision 1.65 2004/10/20 02:15:09 cheshire
-Add case in GetRRDisplayString() to display NS rdata
+Revision 1.154 2007/05/04 20:19:53 cheshire
+Improve DumpPacket() output
-Revision 1.64 2004/10/13 00:24:02 cheshire
-Disable "array is too small to include a terminating null character" warning on Windows
+Revision 1.153 2007/05/01 21:46:31 cheshire
+Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
-Revision 1.63 2004/10/10 06:57:14 cheshire
-Change definition of "localdomain" to make code compile a little smaller
+Revision 1.152 2007/04/27 19:28:01 cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
-Revision 1.62 2004/10/06 01:44:19 cheshire
-<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
+Revision 1.151 2007/04/26 13:35:25 cheshire
+Add kDNSType_SOA case in SameRDataBody, and a comment in GetLargeResourceRecord about why this is important
-Revision 1.61 2004/09/30 00:24:56 ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.150 2007/04/24 00:17:33 cheshire
+Made LocateLLQOptData guard against packets with bogus numAdditionals value
-Revision 1.60 2004/09/27 23:25:30 cheshire
-Fix compiler warning: soa.serial is signed, not unsigned
+Revision 1.149 2007/04/23 21:43:00 cheshire
+Remove debugging check
-Revision 1.59 2004/09/27 22:53:45 ksekar
-Fixed getLargeResourceRecord for SOA rdata.
+Revision 1.148 2007/04/23 04:55:29 cheshire
+Add some defensive null pointer checks
-Revision 1.58 2004/09/25 02:41:39 cheshire
-<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
+Revision 1.147 2007/04/22 20:18:10 cheshire
+Add comment about mDNSRandom()
-Revision 1.57 2004/09/25 02:24:27 cheshire
-Removed unused rr->UseCount
+Revision 1.146 2007/04/22 06:02:02 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.56 2004/09/24 20:57:39 cheshire
-<rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
+Revision 1.145 2007/04/20 21:17:24 cheshire
+For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-Revision 1.55 2004/09/17 01:08:48 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.144 2007/04/19 18:02:43 cheshire
+<rdar://problem/5140504> Unicast DNS response records should tagged with kDNSRecordTypePacketUnique bit
-Revision 1.54 2004/09/17 00:49:51 cheshire
-Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
-is GetLargeResourceRecord
+Revision 1.143 2007/04/16 21:53:49 cheshire
+Improve display of negative cache entries
-Revision 1.53 2004/09/17 00:31:51 cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+Revision 1.142 2007/04/05 22:55:35 cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-Revision 1.52 2004/09/17 00:19:10 cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+Revision 1.141 2007/04/04 01:33:11 cheshire
+<rdar://problem/5075200> DNSServiceAddRecord is failing to advertise NULL record
+Overly defensive code was zeroing too much of the AuthRecord structure
-Revision 1.51 2004/09/16 02:29:39 cheshire
-Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
-uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
-
-Revision 1.50 2004/09/16 01:58:14 cheshire
-Fix compiler warnings
+Revision 1.140 2007/04/03 19:37:58 cheshire
+Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918()
-Revision 1.49 2004/09/14 23:42:35 cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+Revision 1.139 2007/04/03 19:18:39 cheshire
+Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly
-Revision 1.48 2004/09/14 23:27:46 cheshire
-Fix compile errors
+Revision 1.138 2007/03/28 21:14:08 cheshire
+The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
-Revision 1.47 2004/08/25 02:50:04 cheshire
-<rdar://problem/3561220> Browses are no longer piggybacking on other browses
-Make mDNSSameAddress() recognise that two mDNSAddrType_None addresses are necessarily equal
+Revision 1.137 2007/03/28 20:59:26 cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-Revision 1.46 2004/08/18 17:35:40 ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+Revision 1.136 2007/03/28 15:56:37 cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-Revision 1.45 2004/08/15 18:26:00 cheshire
-Don't use strcpy() on "struct domainname" objects; use AssignDomainName() instead
-(A "struct domainname" is a collection of packed pascal strings, not a C string.)
+Revision 1.135 2007/03/28 01:20:05 cheshire
+<rdar://problem/4883206> Improve/create logging for secure browse
-Revision 1.44 2004/08/13 23:46:58 cheshire
-"asyncronous" -> "asynchronous"
+Revision 1.134 2007/03/27 23:25:35 cheshire
+Fix error caching SOA records
+(cache entry was size of wire-format packed data, not size of in-memory structure)
-Revision 1.43 2004/08/12 02:55:46 ksekar
-Fix param order error moving putPrereqNameNotInUse from uDNS.c using
-ustrcpy macro to DNSCommon.c using mDNSPlatformStrCopy().
+Revision 1.133 2007/03/26 22:55:45 cheshire
+Add OPT and TSIG to list of types DNSTypeName() knows about
-Revision 1.42 2004/08/10 23:19:14 ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
+Revision 1.132 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-Revision 1.41 2004/08/10 01:10:01 cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
-Minor revision from Roger Pantos
+Revision 1.131 2007/03/21 21:55:20 cheshire
+<rdar://problem/5069688> Hostname gets ; or : which are illegal characters
+Error in AppendLabelSuffix() for numbers close to the 32-bit limit
-Revision 1.40 2004/08/04 22:10:46 cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
-Change to use "._sub." instead of ".s." to mark subtypes.
+Revision 1.130 2007/03/21 19:23:37 cheshire
+<rdar://problem/5076826> jmDNS advertised garbage that shows up weird in Safari
+Make check less strict so we don't break Bonjour Browser
-Revision 1.39 2004/07/13 21:24:24 rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.129 2007/03/21 01:00:45 cheshire
+<rdar://problem/5076826> jmDNS advertised garbage that shows up weird in Safari
+DeconstructServiceName() needs to be more defensive about what it considers legal
-Revision 1.38 2004/06/18 21:08:58 cheshire
-<rdar://problem/3540040> Applications are registering invalid records
-Attempts to create domain names like "www..apple.com." now logged to aid debugging
+Revision 1.128 2007/03/21 00:30:02 cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
-Revision 1.37 2004/06/18 20:25:42 cheshire
-<rdar://problem/3488547> Add a syslog message if someone tries to use "local.arpa".
+Revision 1.127 2007/03/20 17:07:15 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-Revision 1.36 2004/06/18 19:09:59 cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.126 2007/03/10 03:26:44 cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Revision 1.35 2004/06/05 00:14:44 cheshire
-Fix signed/unsigned and other compiler warnings
+Revision 1.125 2007/03/07 00:08:58 cheshire
+<rdar://problem/4347550> Don't allow hyphens at start of service type
-Revision 1.34 2004/06/04 00:25:25 cheshire
-Fix misaligned write exception that occurs on some platforms
+Revision 1.124 2007/01/19 18:04:05 cheshire
+For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT
-Revision 1.33 2004/06/04 00:16:18 cheshire
-Remove non-portable use of 'inline'
+Revision 1.123 2007/01/10 22:45:51 cheshire
+Cast static strings to "(const domainname*)", not "(domainname*)"
-Revision 1.32 2004/06/03 03:09:58 ksekar
-<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+Revision 1.122 2007/01/06 00:47:35 cheshire
+Improve GetRRDisplayString to indicate when record has zero-length rdata
-Revision 1.31 2004/05/28 23:42:36 ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.121 2007/01/05 08:30:39 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.30 2004/05/26 09:08:04 bradley
-Added cast to correct structure pointer when allocating domain name list element to fix C++ builds.
+Revision 1.120 2007/01/05 05:23:00 cheshire
+Zero DNSQuestion structure in getQuestion (specifically, need TargetQID to be zero'd)
-Revision 1.29 2004/05/18 23:51:25 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.119 2007/01/05 04:30:16 cheshire
+Change a couple of "(domainname *)" casts to "(const domainname *)"
-Revision 1.28 2004/05/13 04:54:20 ksekar
-Unified list copy/free code. Added symetric list for
+Revision 1.118 2007/01/04 20:21:59 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+Don't return multicast answers in response to unicast questions
-Revision 1.27 2004/04/22 20:29:07 cheshire
-Log error message if no count field passed to PutResourceRecordTTL()
+Revision 1.117 2006/12/22 20:59:49 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.26 2004/04/22 04:07:01 cheshire
-Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
+Revision 1.116 2006/12/21 00:04:07 cheshire
+To be defensive, put a mDNSPlatformMemZero() at the start of mDNS_SetupResourceRecord()
-Revision 1.25 2004/04/22 03:05:28 cheshire
-kDNSClass_ANY should be kDNSQClass_ANY
+Revision 1.115 2006/12/20 04:07:34 cheshire
+Remove uDNS_info substructure from AuthRecord_struct
-Revision 1.24 2004/04/22 02:51:20 cheshire
-Use common code for HINFO/TXT and TSIG cases in putRData
-
-Revision 1.23 2004/04/15 00:51:28 bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
-
-Revision 1.22 2004/04/14 23:09:28 ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.114 2006/12/19 22:40:04 cheshire
+Fix compiler warnings
-Revision 1.21 2004/04/09 16:47:28 cheshire
-<rdar://problem/3617655>: mDNSResponder escape handling inconsistent with BIND
+Revision 1.113 2006/12/19 02:21:08 cheshire
+Delete spurious spaces
-Revision 1.20 2004/04/09 16:37:15 cheshire
-Suggestion from Bob Bradley:
-Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+Revision 1.112 2006/12/15 20:42:10 cheshire
+<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
+Additional defensive coding in GetLargeResourceRecord() to reject apparently-valid
+rdata that actually runs past the end of the received packet data.
-Revision 1.19 2004/04/02 19:34:38 cheshire
-Fix broken comment
+Revision 1.111 2006/12/15 19:09:57 cheshire
+<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
+Made DomainNameLength() more defensive by adding a limit parameter, so it can be
+safely used to inspect potentially malformed data received from external sources.
+Without this, a domain name that starts off apparently valid, but extends beyond the end of
+the received packet data, could have appeared valid if the random bytes are already in memory
+beyond the end of the packet just happened to have reasonable values (e.g. all zeroes).
-Revision 1.18 2004/03/30 06:45:00 cheshire
-Compiler warning fixes from Don Woodward at Roku Labs
+Revision 1.110 2006/11/18 05:01:30 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
-Revision 1.17 2004/03/19 22:25:20 cheshire
-<rdar://problem/3579561>: Need to limit service types to fourteen characters
-Won't actually do this for now, but keep the code around just in case
+Revision 1.109 2006/11/10 00:54:14 cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
-Revision 1.16 2004/03/08 02:45:35 cheshire
-Minor change to make a couple of the log messages a bit shorter
+Revision 1.108 2006/10/05 23:11:18 cheshire
+<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-Revision 1.15 2004/03/08 02:44:09 cheshire
-<rdar://problem/3579561>: Need to limit service types to fourteen characters
+Revision 1.107 2006/09/15 21:20:14 cheshire
+Remove uDNS_info substructure from mDNS_struct
-Revision 1.14 2004/02/21 02:06:24 cheshire
-Can't use anonymous unions -- they're non-standard and don't work on all compilers
+Revision 1.106 2006/08/14 23:24:22 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.13 2004/02/06 23:04:18 ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.105 2006/07/15 02:01:28 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
-Revision 1.12 2004/02/03 22:37:10 cheshire
-Delete unused (commented-out) code
+Revision 1.104 2006/07/05 23:09:13 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-Revision 1.11 2004/02/03 22:35:34 cheshire
-<rdar://problem/3548256>: Should not allow empty string for resolve domain
+Revision 1.103 2006/06/29 07:42:14 cheshire
+<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-Revision 1.10 2004/02/03 19:47:36 ksekar
-Added an asynchronous state machine mechanism to uDNS.c, including
-calls to find the parent zone for a domain name. Changes include code
-in repository previously dissabled via "#if 0 incomplete". Codepath
-is currently unused, and will be called to create update records, etc.
+Revision 1.102 2006/06/22 19:49:11 cheshire
+Added (commented out) definitions for the LLMNR UDP port and multicast addresses
-Revision 1.9 2004/01/27 20:15:22 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.101 2006/06/15 21:35:15 cheshire
+Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
+from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
-Revision 1.8 2004/01/24 23:24:36 cheshire
-Expanded out the list of local domains to reduce risk of mistakes in future
+Revision 1.100 2006/06/08 22:58:46 cheshire
+<rdar://problem/4335605> IPv6 link-local address prefix is FE80::/10, not FE80::/16
-Revision 1.7 2004/01/24 08:32:30 bradley
-Mask values with 0xFF before casting to avoid runtime truncation errors on Windows debug builds.
-Separated octal-escaped sequences preceding decimal digits to avoid errors with some compilers wanting
-to signal potentially hidden errors about the subsequent digit not being part of the octal sequence.
+Revision 1.99 2006/05/18 01:32:33 cheshire
+<rdar://problem/4472706> iChat: Lost connection with Bonjour
+(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
-Revision 1.6 2004/01/24 04:59:15 cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.98 2006/03/19 17:00:58 cheshire
+Define symbol MaxMsg instead of using hard-coded constant value '80'
-Revision 1.5 2004/01/23 23:23:14 ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.97 2006/03/18 21:47:56 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-Revision 1.4 2004/01/22 02:15:33 cheshire
-<rdar://problem/3536597>: Link-local reverse-mapping domains need to be resolved using link-local multicast
+Revision 1.96 2006/03/10 21:51:42 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Split out SameRDataBody() into a separate routine so it can be called from other code
-Revision 1.3 2004/01/21 21:16:29 cheshire
-Minor tidy-up: Deleted a bunch of blank lines, trailing spaces, tabs, etc.
+Revision 1.95 2006/03/08 22:43:11 cheshire
+Use "localdomain" symbol instead of literal string
-Revision 1.2 2003/12/13 05:47:48 bradley
-Made local ptr const to fix error when assigning from const structure. Disable benign conditional
-expression is constant warning when building with Microsoft compilers.
+Revision 1.94 2006/03/02 21:59:55 cheshire
+<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
+Improve sanity checks & debugging support in GetLargeResourceRecord()
-Revision 1.1 2003/12/13 03:05:27 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.93 2006/03/02 20:30:47 cheshire
+Improved GetRRDisplayString to also show priority, weight, and port for SRV records
- */
+*/
// Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
#define mDNS_InstantiateInlines 1
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - DNameList copy/deallocation routines
+#pragma mark - Program Constants
#endif
-mDNSexport DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig)
- {
- DNameListElem *copy = mDNSNULL, *newelem;
- const DNameListElem *ptr;
-
- for (ptr = orig; ptr; ptr = ptr->next)
- {
- newelem = (DNameListElem*)mDNSPlatformMemAllocate(sizeof(DNameListElem));
- if (!newelem) { LogMsg("ERROR: malloc"); return mDNSNULL; }
- AssignDomainName(&newelem->name, &ptr->name);
- newelem->next = copy;
- copy = newelem;
- }
- return copy;
- }
-
-mDNSexport void mDNS_FreeDNameList(DNameListElem *list)
- {
- DNameListElem *fptr;
-
- while (list)
- {
- fptr = list;
- list = list->next;
- mDNSPlatformMemFree(fptr);
- }
- }
+mDNSexport const mDNSIPPort zeroIPPort = { { 0 } };
+mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } };
+mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } };
+mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } };
+mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } };
+mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
+mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} };
+
+mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0;
+mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1;
+mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)2;
+
+// Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
+// Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
+// port and multicast address, which means it won't interoperate with the existing installed base of Multicast DNS responders.
+// LLMNR uses IPv4 multicast address 224.0.0.252, IPv6 multicast address FF02::0001:0003, and UDP port 5355.
+// Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability
+// with Microsoft's LLMNR client code.
+
+#define SSDPPortAsNumber 1900
+
+#define UnicastDNSPortAsNumber 53
+#define NATPMPAnnouncementPortAsNumber 5350
+#define NATPMPPortAsNumber 5351
+#define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
+#define MulticastDNSPortAsNumber 5353
+#define LoopbackIPCPortAsNumber 5354
+//#define MulticastDNSPortAsNumber 5355 // LLMNR
+
+#define NSIPCPortAsNumber 5030 // Port used for dnsextd to talk to local nameserver bound to loopback
+#define PrivateDNSPortAsNumber 5533
+
+mDNSexport const mDNSIPPort SSDPPort = { { SSDPPortAsNumber >> 8, SSDPPortAsNumber & 0xFF } };
+
+mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } };
+
+mDNSexport const mDNSIPPort NSIPCPort = { { NSIPCPortAsNumber >> 8, NSIPCPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort PrivateDNSPort = { { PrivateDNSPortAsNumber >> 8, PrivateDNSPortAsNumber & 0xFF } };
+
+mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } };
+mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } };
+//mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 252 } } } }; // LLMNR
+mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
+//mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR
+
+mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
+mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } };
+mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
+mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
+mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
+mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
+
+mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } };
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#endif
// return true for RFC1918 private addresses
-mDNSexport mDNSBool IsPrivateV4Addr(mDNSAddr *addr)
+mDNSexport mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr)
{
- mDNSu8 *b;
-
- if (addr->type != mDNSAddrType_IPv4) return mDNSfalse;
- b = addr->ip.v4.b;
-
- return ((b[0] == 10) || // 10/8 prefix
- (b[0] == 172 && b[1] > 15 && b[1] < 32) || // 172.16/12
- (b[0] == 192 && b[1] == 168)); // 192.168/16
+ return ((addr->b[0] == 10) || // 10/8 prefix
+ (addr->b[0] == 172 && (addr->b[1] & 0xF0) == 16) || // 172.16/12
+ (addr->b[0] == 192 && addr->b[1] == 168)); // 192.168/16
}
mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf)
case kDNSType_TXT: return("TXT");
case kDNSType_AAAA: return("AAAA");
case kDNSType_SRV: return("SRV");
+ case kDNSType_OPT: return("OPT");
+ case kDNSType_TSIG: return("TSIG");
case kDNSQType_ANY: return("ANY");
default: {
static char buffer[16];
// long as this routine is only used for debugging messages, it probably isn't a big problem.
mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer)
{
+ #define Max (MaxMsg-1)
char *ptr = buffer;
- mDNSu32 length = mDNS_snprintf(buffer, 79, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
+ mDNSu32 length = mDNS_snprintf(buffer, Max, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
+ if (rr->RecordType == kDNSRecordTypePacketNegative) return(buffer);
+ if (!rr->rdlength) { mDNS_snprintf(buffer+length, Max-length, "<< ZERO RDATA LENGTH >>"); return(buffer); }
+
switch (rr->rrtype)
{
- case kDNSType_A: mDNS_snprintf(buffer+length, 79-length, "%.4a", &rd->ipv4); break;
+ case kDNSType_A: mDNS_snprintf(buffer+length, Max-length, "%.4a", &rd->ipv4); break;
case kDNSType_NS: // Same as PTR
case kDNSType_CNAME:// Same as PTR
- case kDNSType_PTR: mDNS_snprintf(buffer+length, 79-length, "%##s", rd->name.c); break;
+ case kDNSType_PTR: mDNS_snprintf(buffer+length, Max-length, "%##s", rd->name.c); break;
- case kDNSType_HINFO:// Display this the same as TXT (just show first string)
- case kDNSType_TXT: mDNS_snprintf(buffer+length, 79-length, "%#s", rd->txt.c); break;
+ case kDNSType_SOA: mDNS_snprintf(buffer+length, Max-length, "%##s %##s %d %d %d %d %d",
+ rd->soa.mname.c, rd->soa.rname.c,
+ rd->soa.serial, rd->soa.refresh, rd->soa.retry, rd->soa.expire, rd->soa.min);
+ break;
+
+ case kDNSType_HINFO:// Display this the same as TXT (show all constituent string)
+ case kDNSType_TXT: {
+ mDNSu8 *t = rd->txt.c;
+ while (t < rd->txt.c + rr->rdlength)
+ {
+ length += mDNS_snprintf(buffer+length, Max-length, "%s%#s", t > rd->txt.c ? "¦" : "", t);
+ t += 1 + t[0];
+ }
+ } break;
- case kDNSType_AAAA: mDNS_snprintf(buffer+length, 79-length, "%.16a", &rd->ipv6); break;
- case kDNSType_SRV: mDNS_snprintf(buffer+length, 79-length, "%u %u %u %##s",
+ case kDNSType_AAAA: mDNS_snprintf(buffer+length, Max-length, "%.16a", &rd->ipv6); break;
+ case kDNSType_SRV: mDNS_snprintf(buffer+length, Max-length, "%u %u %u %##s",
rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
- default: mDNS_snprintf(buffer+length, 79-length, "RDLen %d: %s", rr->rdlength, rd->data); break;
+ case kDNSType_OPT: length += mDNS_snprintf(buffer+length, Max-length, "%d Len %d ", rd->opt.opt, rd->opt.optlen);
+ length += mDNS_snprintf(buffer+length, Max-length, "Max UDP %d ", rr->rrclass);
+ if (rd->opt.opt == kDNSOpt_LLQ)
+ {
+ length += mDNS_snprintf(buffer+length, Max-length, "Vers %d ", rd->opt.OptData.llq.vers);
+ length += mDNS_snprintf(buffer+length, Max-length, "Op %d ", rd->opt.OptData.llq.llqOp);
+ length += mDNS_snprintf(buffer+length, Max-length, "Err/Port %d ", rd->opt.OptData.llq.err);
+ length += mDNS_snprintf(buffer+length, Max-length, "ID %08X%08X ", rd->opt.OptData.llq.id.l[0], rd->opt.OptData.llq.id.l[1]);
+ length += mDNS_snprintf(buffer+length, Max-length, "Lease %d", rd->opt.OptData.llq.llqlease);
+ }
+ else if (rd->opt.opt == kDNSOpt_Lease)
+ length += mDNS_snprintf(buffer+length, Max-length, "kDNSOpt_Lease Lease %d", rd->opt.OptData.updatelease);
+ else
+ length += mDNS_snprintf(buffer+length, Max-length, "Unknown opt %d", rd->opt.opt);
+ break;
+ default: mDNS_snprintf(buffer+length, Max-length, "RDLen %d: %s", rr->rdlength, rd->data);
+ // Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not
+ for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.';
+ break;
}
- for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
return(buffer);
}
-mDNSexport mDNSu32 mDNSRandom(mDNSu32 max)
+mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) // Returns pseudo-random result from zero to max inclusive
{
static mDNSu32 seed = 0;
mDNSu32 mask = 1;
return (seed & mask);
}
+mDNSexport mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max)
+ {
+ mDNSu32 mask = 1;
+ while (mask < max) mask = (mask << 1) | 1;
+ do seed = seed * 21 + 1; while ((seed & mask) > max);
+ return (seed & mask);
+ }
+
mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
{
if (ip1->type == ip2->type)
{
switch(ip->type)
{
- case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroupv4.NotAnInteger);
- case mDNSAddrType_IPv6: return(mDNSBool)(ip->ip.v6.l[0] == AllDNSLinkGroupv6.l[0] &&
- ip->ip.v6.l[1] == AllDNSLinkGroupv6.l[1] &&
- ip->ip.v6.l[2] == AllDNSLinkGroupv6.l[2] &&
- ip->ip.v6.l[3] == AllDNSLinkGroupv6.l[3] );
+ case mDNSAddrType_IPv4: return(mDNSBool)(mDNSSameIPv4Address(ip->ip.v4, AllDNSLinkGroup_v4.ip.v4));
+ case mDNSAddrType_IPv6: return(mDNSBool)(mDNSSameIPv6Address(ip->ip.v6, AllDNSLinkGroup_v6.ip.v6));
default: return(mDNSfalse);
}
}
return(mDNStrue);
}
+mDNSexport mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2)
+ {
+ mDNSu16 l1 = DomainNameLength(d1);
+ mDNSu16 l2 = DomainNameLength(d2);
+ return(l1 <= MAX_DOMAIN_NAME && l1 == l2 && mDNSPlatformMemSame(d1, d2, l1));
+ }
+
mDNSexport mDNSBool IsLocalDomain(const domainname *d)
{
// Domains that are defined to be resolved via link-local multicast are:
- // local., 254.169.in-addr.arpa., and 0.8.E.F.ip6.arpa.
- static const domainname *n0 = (domainname*)"\x5" "local";
- static const domainname *n1 = (domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa";
- static const domainname *n2 = (domainname*)"\x1" "0" "\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
-
- const domainname *d1, *d2, *d3, *d4, *d5, *d6; // Top-level domain, second-level domain, etc.
- d1 = d2 = d3 = d4 = d5 = d6 = mDNSNULL;
+ // local., 254.169.in-addr.arpa., and {8,9,A,B}.E.F.ip6.arpa.
+ static const domainname *nL = (const domainname*)"\x5" "local";
+ static const domainname *nR = (const domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa";
+ static const domainname *n8 = (const domainname*)"\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
+ static const domainname *n9 = (const domainname*)"\x1" "9" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
+ static const domainname *nA = (const domainname*)"\x1" "a" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
+ static const domainname *nB = (const domainname*)"\x1" "b" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa";
+
+ const domainname *d1, *d2, *d3, *d4, *d5; // Top-level domain, second-level domain, etc.
+ d1 = d2 = d3 = d4 = d5 = mDNSNULL;
while (d->c[0])
{
- d6 = d5; d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
- d = (domainname*)(d->c + 1 + d->c[0]);
+ d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
+ d = (const domainname*)(d->c + 1 + d->c[0]);
}
- if (d1 && SameDomainName(d1, n0)) return(mDNStrue);
- if (d4 && SameDomainName(d4, n1)) return(mDNStrue);
- if (d6 && SameDomainName(d6, n2)) return(mDNStrue);
+ if (d1 && SameDomainName(d1, nL)) return(mDNStrue);
+ if (d4 && SameDomainName(d4, nR)) return(mDNStrue);
+ if (d5 && SameDomainName(d5, n8)) return(mDNStrue);
+ if (d5 && SameDomainName(d5, n9)) return(mDNStrue);
+ if (d5 && SameDomainName(d5, nA)) return(mDNStrue);
+ if (d5 && SameDomainName(d5, nB)) return(mDNStrue);
return(mDNSfalse);
}
// Returns length of a domain name INCLUDING the byte for the final null label
-// i.e. for the root label "." it returns one
+// e.g. for the root label "." it returns one
// For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
// Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME)
-// If the given domainname is invalid, result is 256
-mDNSexport mDNSu16 DomainNameLength(const domainname *const name)
+// If the given domainname is invalid, result is 256 (MAX_DOMAIN_NAME+1)
+mDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit)
{
const mDNSu8 *src = name->c;
- while (*src)
+ while (src < limit && *src <= MAX_DOMAIN_LABEL)
{
- if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
+ if (*src == 0) return((mDNSu16)(src - name->c + 1));
src += 1 + *src;
- if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
}
- return((mDNSu16)(src - name->c + 1));
+ return(MAX_DOMAIN_NAME+1);
}
// CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
-// for the final null label i.e. for the root label "." it returns one.
+// for the final null label, e.g. for the root label "." it returns one.
// E.g. for the FQDN "foo.com." it returns 9
// (length, three data bytes, length, three more data bytes, final zero).
// In the case where a parent domain name is provided, and the given name is a child
while (*src)
{
if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
- if (parent && SameDomainName((domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
+ if (parent && SameDomainName((const domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
src += 1 + *src;
if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
}
return((mDNSu16)(src - name->c + 1));
}
+// CountLabels() returns number of labels in name, excluding final root label
+// (e.g. for "apple.com." CountLabels returns 2.)
+mDNSexport int CountLabels(const domainname *d)
+ {
+ int count = 0;
+ const mDNSu8 *ptr;
+ for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
+ return count;
+ }
+
+// SkipLeadingLabels skips over the first 'skip' labels in the domainname,
+// returning a pointer to the suffix with 'skip' labels removed.
+mDNSexport const domainname *SkipLeadingLabels(const domainname *d, int skip)
+ {
+ while (skip > 0 && d->c[0]) { d = (const domainname *)(d->c + 1 + d->c[0]); skip--; }
+ return(d);
+ }
+
// AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
// The C string contains the label as-is, with no escaping, etc.
// Any dots in the name are literal dots, not label separators
// If successful, AppendLiteralLabelString returns a pointer to the next unused byte
-// in the domainname bufer (i.e., the next byte after the terminating zero).
+// in the domainname bufer (i.e. the next byte after the terminating zero).
// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
// AppendLiteralLabelString returns mDNSNULL.
mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
// The C string is in conventional DNS syntax:
// Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
// If successful, AppendDNSNameString returns a pointer to the next unused byte
-// in the domainname bufer (i.e., the next byte after the terminating zero).
+// in the domainname bufer (i.e. the next byte after the terminating zero).
// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
// AppendDNSNameString returns mDNSNULL.
mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring)
// AppendDomainLabel appends a single label to a name.
// If successful, AppendDomainLabel returns a pointer to the next unused byte
-// in the domainname bufer (i.e., the next byte after the terminating zero).
+// in the domainname bufer (i.e. the next byte after the terminating zero).
// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
// AppendDomainLabel returns mDNSNULL.
mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name
const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero)
const mDNSu8 * src = append->c;
- while(src[0])
+ while (src[0])
{
int i;
if (ptr + 1 + src[0] > lim) return(mDNSNULL);
// The C string is in conventional DNS syntax:
// Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
// If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
-// in the domainname bufer (i.e., the next byte after the terminating zero).
+// in the domainname bufer (i.e. the next byte after the terminating zero).
// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes)
// MakeDomainNameFromDNSNameString returns mDNSNULL.
mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
}
+#define ValidTransportProtocol(X) ( (X)[0] == 4 && (X)[1] == '_' && \
+ ((((X)[2] | 0x20) == 'u' && ((X)[3] | 0x20) == 'd') || (((X)[2] | 0x20) == 't' && ((X)[3] | 0x20) == 'c')) && \
+ ((X)[4] | 0x20) == 'p')
+
mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
const domainlabel *name, const domainname *type, const domainname *const domain)
{
len = *src;
for (i=0; i <= len; i++) *dst++ = *src++;
for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i];
- type = (domainname *)s1;
+ type = (const domainname *)s1;
- // Special support for queries done by some third-party network monitoring software
+ // Special support to enable the DNSServiceBrowse call made by Bonjour Browser
// For these queries, we retract the "._sub" we just added between the subtype and the main type
- if (SameDomainName((domainname*)s0, (domainname*)"\x09_services\x07_dns-sd\x04_udp") ||
- SameDomainName((domainname*)s0, (domainname*)"\x09_services\x05_mdns\x04_udp"))
+ // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
+ if (SameDomainName((domainname*)s0, (const domainname*)"\x09_services\x07_dns-sd\x04_udp"))
dst -= sizeof(SubTypeLabel);
}
}
{
src = name->c; // Put the service name into the domain name
len = *src;
- if (len >= 0x40) { errormsg="Service instance name too long"; goto fail; }
+ if (len >= 0x40) { errormsg = "Service instance name too long"; goto fail; }
for (i=0; i<=len; i++) *dst++ = *src++;
}
else
len = *src;
if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain)))
{
- errormsg="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
+ errormsg = "Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
goto fail;
}
- if (src[1] != '_') { errormsg="Application protocol name must begin with underscore"; goto fail; }
+ if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; }
for (i=2; i<=len; i++)
- if (!mdnsIsLetter(src[i]) && !mdnsIsDigit(src[i]) && src[i] != '-' && src[i] != '_')
- { errormsg="Application protocol name must contain only letters, digits, and hyphens"; goto fail; }
+ {
+ // Letters and digits are allowed anywhere
+ if (mdnsIsLetter(src[i]) || mdnsIsDigit(src[i])) continue;
+ // Hyphens are only allowed as interior characters
+ // Underscores are not supposed to be allowed at all, but for backwards compatibility with some old products we do allow them,
+ // with the same rule as hyphens
+ if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len) continue;
+ errormsg = "Application protocol name must contain only letters, digits, and hyphens"; goto fail;
+ }
for (i=0; i<=len; i++) *dst++ = *src++;
len = *src;
- if (!(len == 4 && src[1] == '_' &&
- (((src[2] | 0x20) == 'u' && (src[3] | 0x20) == 'd') || ((src[2] | 0x20) == 't' && (src[3] | 0x20) == 'c')) &&
- (src[4] | 0x20) == 'p'))
- { errormsg="Transport protocol name must be _udp or _tcp"; goto fail; }
+ if (!ValidTransportProtocol(src)) { errormsg = "Transport protocol name must be _udp or _tcp"; goto fail; }
for (i=0; i<=len; i++) *dst++ = *src++;
- if (*src) { errormsg="Service type must have only two labels"; goto fail; }
+ if (*src) { errormsg = "Service type must have only two labels"; goto fail; }
*dst = 0;
- if (!domain->c[0]) { errormsg="Service domain must be non-empty"; goto fail; }
- if (SameDomainName(domain, (domainname*)"\x05" "local" "\x04" "arpa"))
- { errormsg="Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
+ if (!domain->c[0]) { errormsg = "Service domain must be non-empty"; goto fail; }
+ if (SameDomainName(domain, (const domainname*)"\x05" "local" "\x04" "arpa"))
+ { errormsg = "Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
dst = AppendDomainName(fqdn, domain);
- if (!dst) { errormsg="Service domain too long"; goto fail; }
+ if (!dst) { errormsg = "Service domain too long"; goto fail; }
return(dst);
fail:
dst = name->c; // Extract the service name
len = *src;
- if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); }
- if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); }
+ if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); }
+ if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); }
for (i=0; i<=len; i++) *dst++ = *src++;
dst = type->c; // Extract the service type
len = *src;
- if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); }
- if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); }
+ if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); }
+ if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); }
+ if (src[1] != '_'){ debugf("DeconstructServiceName: No _ at start of application protocol"); return(mDNSfalse); }
for (i=0; i<=len; i++) *dst++ = *src++;
len = *src;
- if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); }
- if (len >= 0x40) { debugf("DeconstructServiceName: Transport protocol name too long"); return(mDNSfalse); }
+ if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); }
+ // Can't do this check right now, until Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
+ //if (!ValidTransportProtocol(src))
+ // { debugf("DeconstructServiceName: Transport protocol must be _udp or _tcp"); return(mDNSfalse); }
for (i=0; i<=len; i++) *dst++ = *src++;
*dst++ = 0; // Put terminator on the end of service type
{
if (length > max)
{
- mDNSu8 c1 = string[max]; // First byte after cut point
- mDNSu8 c2 = (max+1 < length) ? string[max+1] : 0xB0; // Second byte after cut point
+ mDNSu8 c1 = string[max]; // First byte after cut point
+ mDNSu8 c2 = (max+1 < length) ? string[max+1] : (mDNSu8)0xB0; // Second byte after cut point
length = max; // Trim length down
while (length > 0)
{
// appends a numerical suffix to a label, with the number following a whitespace and enclosed
// in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
-mDNSexport void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
+mDNSexport void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText)
{
mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2")
if (RichText) chars = 4; // Shortest possible RichText suffix is 4 characters (" (2)")
// Truncate trailing spaces from RichText names
if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--;
- while (val >= divisor * 10) { divisor *= 10; chars++; }
+ while (divisor < 0xFFFFFFFFUL/10 && val >= divisor * 10) { divisor *= 10; chars++; }
name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars);
#pragma mark - Resource Record Utility Functions
#endif
+// Set up a AuthRecord with sensible default values.
+// These defaults may be overwritten with new values before mDNS_Register is called
+mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
+ mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
+ {
+ // Don't try to store a TTL bigger than we can represent in platform time units
+ if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
+ ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
+ else if (ttl == 0) // And Zero TTL is illegal
+ ttl = DefaultTTLforRRType(rrtype);
+
+ // Field Group 1: The actual information pertaining to this resource record
+ rr->resrec.RecordType = RecordType;
+ rr->resrec.InterfaceID = InterfaceID;
+ rr->resrec.name = &rr->namestorage;
+ rr->resrec.rrtype = rrtype;
+ rr->resrec.rrclass = kDNSClass_IN;
+ rr->resrec.rroriginalttl = ttl;
+// rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal
+// rr->resrec.rdestimate = set in mDNS_Register_internal
+// rr->resrec.rdata = MUST be set by client
+
+ if (RDataStorage)
+ rr->resrec.rdata = RDataStorage;
+ else
+ {
+ rr->resrec.rdata = &rr->rdatastorage;
+ rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
+ }
+
+ // Field Group 2: Persistent metadata for Authoritative Records
+ rr->Additional1 = mDNSNULL;
+ rr->Additional2 = mDNSNULL;
+ rr->DependentOn = mDNSNULL;
+ rr->RRSet = mDNSNULL;
+ rr->RecordCallback = Callback;
+ rr->RecordContext = Context;
+
+ rr->AutoTarget = Target_Manual;
+ rr->AllowRemoteQuery = mDNSfalse;
+ rr->ForceMCast = mDNSfalse;
+
+ // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
+ // Field Group 4: Transient uDNS state for Authoritative Records (set in mDNS_Register_internal)
+
+ // For now, until the uDNS code is fully integrated, it's helpful to zero the uDNS state fields here too, just in case
+ // (e.g. uDNS_RegisterService short-circuits the usual mDNS_Register_internal record registration calls, so a bunch
+ // of fields don't get set up properly. In particular, if we don't zero rr->QueuedRData then the uDNS code crashes.)
+ rr->state = regState_Zero;
+ rr->uselease = 0;
+ rr->expire = 0;
+ rr->Private = 0;
+ rr->id = zeroID;
+ rr->zone.c[0] = 0;
+ rr->UpdateServer = zeroAddr;
+ rr->UpdatePort = zeroIPPort;
+ rr->nta = mDNSNULL;
+ rr->tcp = mDNSNULL;
+ rr->OrigRData = 0;
+ rr->OrigRDLen = 0;
+ rr->InFlightRData = 0;
+ rr->InFlightRDLen = 0;
+ rr->QueuedRData = 0;
+ rr->QueuedRDLen = 0;
+
+ rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register()
+ }
+
mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb)
{
mDNSu32 sum = 0;
{
switch(r1->rrtype)
{
- case kDNSType_CNAME:// Same as PTR
- case kDNSType_PTR: return(SameDomainName(&r1->rdata->u.name, &r2->name));
-
- case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->srv.priority &&
- r1->rdata->u.srv.weight == r2->srv.weight &&
- r1->rdata->u.srv.port.NotAnInteger == r2->srv.port.NotAnInteger &&
- SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target) );
+ case kDNSType_NS:
+ case kDNSType_CNAME:
+ case kDNSType_PTR:
+ case kDNSType_DNAME:return(SameDomainName(&r1->rdata->u.name, &r2->name));
+
+ case kDNSType_SOA: return(mDNSBool)( r1->rdata->u.soa.serial == r2->soa.serial &&
+ r1->rdata->u.soa.refresh == r2->soa.refresh &&
+ r1->rdata->u.soa.retry == r2->soa.retry &&
+ r1->rdata->u.soa.expire == r2->soa.expire &&
+ r1->rdata->u.soa.min == r2->soa.min &&
+ SameDomainName(&r1->rdata->u.soa.mname, &r2->soa.mname) &&
+ SameDomainName(&r1->rdata->u.soa.rname, &r2->soa.rname));
+
+ case kDNSType_MX:
+ case kDNSType_AFSDB:
+ case kDNSType_RT:
+ case kDNSType_KX: return(mDNSBool)( r1->rdata->u.mx.preference == r2->mx.preference &&
+ SameDomainName(&r1->rdata->u.mx.exchange, &r2->mx.exchange));
+
+ case kDNSType_RP: return(mDNSBool)( SameDomainName(&r1->rdata->u.rp.mbox, &r2->rp.mbox) &&
+ SameDomainName(&r1->rdata->u.rp.txt, &r2->rp.txt));
+
+ case kDNSType_PX: return(mDNSBool)( r1->rdata->u.px.preference == r2->px.preference &&
+ SameDomainName(&r1->rdata->u.px.map822, &r2->px.map822) &&
+ SameDomainName(&r1->rdata->u.px.mapx400, &r2->px.mapx400));
+
+ case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->srv.priority &&
+ r1->rdata->u.srv.weight == r2->srv.weight &&
+ mDNSSameIPPort(r1->rdata->u.srv.port, r2->srv.port) &&
+ SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target));
+
+ case kDNSType_OPT: // Okay to use memory compare because there are no 'holes' in the in-memory representation
default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength));
}
mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
{
return (r1->namehash == r2->namehash &&
- r1->rrtype == r2->rrtype &&
+ r1->rrtype == r2->rrtype &&
SameDomainName(r1->name, r2->name) &&
SameRData(r1, r2));
}
+// ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question.
+// SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call.
+// SameDomainName() is generally cheap when the names don't match, but expensive when they do match,
+// because it has to check all the way to the end of the names to be sure.
+// In cases where we know in advance that the names match it's especially advantageous to skip the
+// SameDomainName() call because that's precisely the time when it's most expensive and least useful.
+
+mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+ {
+ if (rr->InterfaceID &&
+ q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
+ rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
+
+ // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
+ if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
+
+ // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
+ if (rr->rrtype != kDNSType_CNAME && rr->rrtype != q->qtype && q->qtype != kDNSQType_ANY ) return(mDNSfalse);
+ if ( rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
+
+#if VerifySameNameAssumptions
+ if (rr->namehash != q->qnamehash || !SameDomainName(rr->name, &q->qname))
+ {
+ LogMsg("Bogus SameNameRecordAnswersQuestion call: RR %##s does not match Q %##s", rr->name->c, q->qname.c);
+ return(mDNSfalse);
+ }
+#endif
+
+ return(mDNStrue);
+ }
+
mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
{
if (rr->InterfaceID &&
q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
+ // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
+ if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
+
// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
if (rr->rrtype != kDNSType_CNAME && rr->rrtype != q->qtype && q->qtype != kDNSQType_ANY ) return(mDNSfalse);
if ( rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
{
const RDataBody *rd = &rr->rdata->u;
const domainname *const name = estimate ? rr->name : mDNSNULL;
- switch (rr->rrtype)
+ if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength); // Used in update packets to mean "Delete An RRset" (RFC 2136)
+ else switch (rr->rrtype)
{
case kDNSType_A: return(sizeof(rd->ipv4));
- case kDNSType_CNAME:// Same as PTR
- case kDNSType_NS: // Same as PTR
- case kDNSType_PTR: return(CompressedDomainNameLength(&rd->name, name));
+
+ case kDNSType_NS:
+ case kDNSType_CNAME:
+ case kDNSType_PTR:
+ case kDNSType_DNAME:return(CompressedDomainNameLength(&rd->name, name));
+
+ case kDNSType_SOA: return(mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
+ CompressedDomainNameLength(&rd->soa.rname, name) +
+ 5 * sizeof(mDNSOpaque32));
+
+ case kDNSType_NULL:
+ case kDNSType_TSIG:
+ case kDNSType_TXT:
+ case kDNSType_X25:
+ case kDNSType_ISDN:
+ case kDNSType_LOC:
+ case kDNSType_DHCID:return(rr->rdlength); // Not self-describing, so have to just trust rdlength
+
case kDNSType_HINFO:return(mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
- case kDNSType_NULL: // Same as TXT -- not self-describing, so have to just trust rdlength
- case kDNSType_TXT: return(rr->rdlength); // TXT is not self-describing, so have to just trust rdlength
+
+ case kDNSType_MX:
+ case kDNSType_AFSDB:
+ case kDNSType_RT:
+ case kDNSType_KX: return(mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name));
+
+ case kDNSType_RP: return(mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) +
+ CompressedDomainNameLength(&rd->rp.txt, name));
+
+ case kDNSType_PX: return(mDNSu16)(2 + CompressedDomainNameLength(&rd->px.map822, name) +
+ CompressedDomainNameLength(&rd->px.mapx400, name));
+
case kDNSType_AAAA: return(sizeof(rd->ipv6));
+
case kDNSType_SRV: return(mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
- case kDNSType_SOA: return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
- CompressedDomainNameLength(&rd->soa.rname, name) +
- 5 * sizeof(mDNSOpaque32));
+
case kDNSType_OPT: return(rr->rdlength);
+
default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
return(rr->rdlength);
}
case kDNSType_MR: // Same as PTR
//case kDNSType_NULL not checked (no specified format, so always valid)
//case kDNSType_WKS not checked
- case kDNSType_PTR: if (!rdlength) return(mDNSfalse);
- len = DomainNameLength(&rd->u.name);
+ case kDNSType_PTR: len = DomainNameLengthLimit(&rd->u.name, rd->u.data + rdlength);
return(len <= MAX_DOMAIN_NAME && rdlength == len);
case kDNSType_HINFO:// Same as TXT (roughly)
case kDNSType_AAAA: return(rdlength == sizeof(mDNSv6Addr));
- case kDNSType_MX: if (!rdlength) return(mDNSfalse);
- len = DomainNameLength(&rd->u.mx.exchange);
+ case kDNSType_MX: // Must be at least two-byte preference, plus domainname
+ // Call to DomainNameLengthLimit() implicitly enforces both requirements for us
+ len = DomainNameLengthLimit(&rd->u.mx.exchange, rd->u.data + rdlength);
return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
- case kDNSType_SRV: if (!rdlength) return(mDNSfalse);
- len = DomainNameLength(&rd->u.srv.target);
+ case kDNSType_SRV: // Must be at least priority+weight+port, plus domainname
+ // Call to DomainNameLengthLimit() implicitly enforces both requirements for us
+ len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength);
return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
default: return(mDNStrue); // Allow all other types without checking
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
-#pragma mark -
#pragma mark - DNS Message Creation Functions
#endif
const mDNSu8 * pointer = mDNSNULL;
const mDNSu8 *const searchlimit = ptr;
+ if (!ptr) { LogMsg("putDomainNameAsLabels ptr is null"); return(mDNSNULL); }
+
while (*np && ptr < limit-1) // While we've got characters in the name, and space to write them in the message...
{
if (*np > MAX_DOMAIN_LABEL)
return ptr + sizeof(mDNSu32);
}
-mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr)
+mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, const ResourceRecord *const rr)
{
int nput = 0;
- rdataOpt *opt;
+ rdataOPT *opt;
while (nput < rr->rdlength)
{
// check if space for opt/optlen
if (ptr + (2 * sizeof(mDNSu16)) > limit) goto space_err;
- opt = (rdataOpt *)(rr->rdata->u.data + nput);
+ opt = (rdataOPT *)(rr->rdata->u.data + nput);
ptr = putVal16(ptr, opt->opt);
ptr = putVal16(ptr, opt->optlen);
nput += 2 * sizeof(mDNSu16);
ptr = putVal16(ptr, opt->OptData.llq.vers);
ptr = putVal16(ptr, opt->OptData.llq.llqOp);
ptr = putVal16(ptr, opt->OptData.llq.err);
- mDNSPlatformMemCopy(opt->OptData.llq.id, ptr, 8); // 8-byte id
+ mDNSPlatformMemCopy(ptr, opt->OptData.llq.id.b, 8); // 8-byte id
ptr += 8;
- ptr = putVal32(ptr, opt->OptData.llq.lease);
+ ptr = putVal32(ptr, opt->OptData.llq.llqlease);
nput += LLQ_OPTLEN;
}
else if (opt->opt == kDNSOpt_Lease)
{
if (ptr + sizeof(mDNSs32) > limit) goto space_err;
- ptr = putVal32(ptr, opt->OptData.lease);
+ ptr = putVal32(ptr, opt->OptData.updatelease);
nput += sizeof(mDNSs32);
}
else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; }
{
int nread = 0;
ResourceRecord *const rr = &cr->r.resrec;
- rdataOpt *opt = (rdataOpt *)rr->rdata->u.data;
+ rdataOPT *opt = (rdataOPT *)rr->rdata->u.data;
- while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOpt))
+ while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOPT))
{
// space for opt + optlen
if (nread + (2 * sizeof(mDNSu16)) > rr->rdata->MaxRDLength) goto space_err;
opt->OptData.llq.vers = getVal16(&ptr);
opt->OptData.llq.llqOp = getVal16(&ptr);
opt->OptData.llq.err = getVal16(&ptr);
- mDNSPlatformMemCopy(ptr, opt->OptData.llq.id, 8);
+ mDNSPlatformMemCopy(opt->OptData.llq.id.b, ptr, 8);
ptr += 8;
- opt->OptData.llq.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
- if (opt->OptData.llq.lease > 0x70000000UL / mDNSPlatformOneSecond)
- opt->OptData.llq.lease = 0x70000000UL / mDNSPlatformOneSecond;
+ opt->OptData.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
+ if (opt->OptData.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
+ opt->OptData.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
ptr += sizeof(mDNSOpaque32);
nread += LLQ_OPTLEN;
}
{
if ((unsigned)(limit - ptr) < sizeof(mDNSs32)) goto space_err;
- opt->OptData.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
- if (opt->OptData.lease > 0x70000000UL / mDNSPlatformOneSecond)
- opt->OptData.lease = 0x70000000UL / mDNSPlatformOneSecond;
+ opt->OptData.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
+ if (opt->OptData.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
+ opt->OptData.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
ptr += sizeof(mDNSs32);
nread += sizeof(mDNSs32);
}
return mDNSNULL;
}
-mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr)
+// msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
+mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr)
{
switch (rr->rrtype)
{
*ptr++ = rr->rdata->u.ipv4.b[3];
return(ptr);
- case kDNSType_CNAME:// Same as PTR
- case kDNSType_PTR: return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
+ case kDNSType_NS:
+ case kDNSType_CNAME:
+ case kDNSType_PTR:
+ case kDNSType_DNAME:return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name));
+
+ case kDNSType_SOA: ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.mname);
+ if (!ptr) return(mDNSNULL);
+ ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.rname);
+ if (!ptr || ptr + 20 > limit) return(mDNSNULL);
+ ptr = putVal32(ptr, rr->rdata->u.soa.serial);
+ ptr = putVal32(ptr, rr->rdata->u.soa.refresh);
+ ptr = putVal32(ptr, rr->rdata->u.soa.retry);
+ ptr = putVal32(ptr, rr->rdata->u.soa.expire);
+ ptr = putVal32(ptr, rr->rdata->u.soa.min);
+ return(ptr);
+
+ case kDNSType_NULL:
+ case kDNSType_HINFO:
+ case kDNSType_TSIG:
+ case kDNSType_TXT:
+ case kDNSType_X25:
+ case kDNSType_ISDN:
+ case kDNSType_LOC:
+ case kDNSType_DHCID:if (ptr + rr->rdlength > limit) return(mDNSNULL);
+ mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength);
+ return(ptr + rr->rdlength);
+
+ case kDNSType_MX:
+ case kDNSType_AFSDB:
+ case kDNSType_RT:
+ case kDNSType_KX: if (ptr + 3 > limit) return(mDNSNULL);
+ ptr = putVal16(ptr, rr->rdata->u.mx.preference);
+ return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.mx.exchange));
+
+ case kDNSType_RP: ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.mbox);
+ if (!ptr) return(mDNSNULL);
+ ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.txt);
+ return(ptr);
+
+ case kDNSType_PX: if (ptr + 5 > limit) return(mDNSNULL);
+ ptr = putVal16(ptr, rr->rdata->u.px.preference);
+ ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.px.map822);
+ if (!ptr) return(mDNSNULL);
+ ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.px.mapx400);
+ return(ptr);
case kDNSType_AAAA: if (rr->rdlength != sizeof(rr->rdata->u.ipv6))
{
return(mDNSNULL);
}
if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL);
- mDNSPlatformMemCopy(&rr->rdata->u.ipv6, ptr, sizeof(rr->rdata->u.ipv6));
+ mDNSPlatformMemCopy(ptr, &rr->rdata->u.ipv6, sizeof(rr->rdata->u.ipv6));
return(ptr + sizeof(rr->rdata->u.ipv6));
- case kDNSType_SRV: if (ptr + 6 > limit) return(mDNSNULL);
+ case kDNSType_SRV: if (ptr + 7 > limit) return(mDNSNULL);
*ptr++ = (mDNSu8)(rr->rdata->u.srv.priority >> 8);
*ptr++ = (mDNSu8)(rr->rdata->u.srv.priority & 0xFF);
*ptr++ = (mDNSu8)(rr->rdata->u.srv.weight >> 8);
*ptr++ = rr->rdata->u.srv.port.b[0];
*ptr++ = rr->rdata->u.srv.port.b[1];
return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.srv.target));
+
case kDNSType_OPT: return putOptRData(ptr, limit, rr);
default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
- // Fall through to common code below
- case kDNSType_HINFO:
- case kDNSType_TXT:
- case kDNSType_TSIG: if (ptr + rr->rdlength > limit) return(mDNSNULL);
- mDNSPlatformMemCopy(rr->rdata->u.data, ptr, rr->rdlength);
+ if (ptr + rr->rdlength > limit) return(mDNSNULL);
+ mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength);
return(ptr + rr->rdlength);
}
}
mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
{
+ mDNSu16 rrclass = (rr->rrtype == kDNSType_OPT) ? NormalMaxDNSMessageData : rr->rrclass;
mDNSu8 *endofrdata;
mDNSu16 actualLength;
return(ptr);
}
+ if (!ptr) { LogMsg("PutResourceRecordTTLWithLimit ptr is null"); return(mDNSNULL); }
+
ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
if (!ptr || ptr + 10 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL
ptr[0] = (mDNSu8)(rr->rrtype >> 8);
ptr[1] = (mDNSu8)(rr->rrtype & 0xFF);
- ptr[2] = (mDNSu8)(rr->rrclass >> 8);
- ptr[3] = (mDNSu8)(rr->rrclass & 0xFF);
+ ptr[2] = (mDNSu8)(rrclass >> 8);
+ ptr[3] = (mDNSu8)(rrclass & 0xFF);
ptr[4] = (mDNSu8)((ttl >> 24) & 0xFF);
ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF);
ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF);
}
// for dynamic updates
-mDNSexport mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end)
+mDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end)
{
AuthRecord prereq;
-
- mDNSPlatformMemZero(&prereq, sizeof(AuthRecord));
mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
- AssignDomainName(prereq.resrec.name, name);
+ AssignDomainName(&prereq.namestorage, name);
prereq.resrec.rrtype = kDNSQType_ANY;
prereq.resrec.rrclass = kDNSClass_NONE;
- ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
- return ptr;
+ return putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
}
// for dynamic updates
mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
{
- mDNSu16 origclass;
// deletion: specify record w/ TTL 0, class NONE
-
- origclass = rr->rrclass;
+ const mDNSu16 origclass = rr->rrclass;
rr->rrclass = kDNSClass_NONE;
ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
rr->rrclass = origclass;
mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
{
AuthRecord rr;
- ResourceRecord *opt = &rr.resrec;
- rdataOpt *optRD;
-
- mDNSPlatformMemZero(&rr, sizeof(AuthRecord));
- mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, 0, mDNSNULL, mDNSNULL);
-
- opt->RecordType = kDNSRecordTypeKnownUnique; // to avoid warnings in other layers
- opt->rrtype = kDNSType_OPT;
- opt->rdlength = LEASE_OPT_RDLEN;
- opt->rdestimate = LEASE_OPT_RDLEN;
-
- optRD = &rr.resrec.rdata->u.opt;
- optRD->opt = kDNSOpt_Lease;
- optRD->optlen = sizeof(mDNSs32);
- optRD->OptData.lease = lease;
- end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, opt, 0);
+ mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+ rr.resrec.rrclass = NormalMaxDNSMessageData;
+ rr.resrec.rdlength = LEASE_OPT_RDLEN;
+ rr.resrec.rdestimate = LEASE_OPT_RDLEN;
+ rr.resrec.rdata->u.opt.opt = kDNSOpt_Lease;
+ rr.resrec.rdata->u.opt.optlen = sizeof(mDNSs32);
+ rr.resrec.rdata->u.opt.OptData.updatelease = lease;
+ end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, &rr.resrec, 0);
if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
-
return end;
}
return(ptr + pktrdlength);
}
-mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
+mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr)
{
CacheRecord *rr = &largecr->r;
rr->NextInCFList = mDNSNULL;
rr->resrec.InterfaceID = InterfaceID;
- ptr = getDomainName(msg, ptr, end, rr->resrec.name);
- if (!ptr) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL); }
+ ptr = getDomainName(msg, ptr, end, &largecr->namestorage);
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
- if (ptr + 10 > end) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
+ if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]);
rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask);
// Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
// us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
- if (ptr[2] & (kDNSClass_UniqueRRSet >> 8))
+
+ // If mDNS record has cache-flush bit set, we mark it unique
+ // For uDNS records, all are implicitly deemed unique (a single DNS server is always
+ // authoritative for the entire RRSet), unless this is a truncated response
+ if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || (!InterfaceID && !(msg->h.flags.b[0] & kDNSFlag0_TC)))
RecordType |= kDNSRecordTypePacketUniqueMask;
ptr += 10;
- if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
+ if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record
rr->resrec.rdata = (RData*)&rr->rdatastorage;
if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
- switch (rr->resrec.rrtype)
+ // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have
+ // a corresponding case in SameRDataBody() to do a semantic comparison of the structure instead of a blind
+ // bitwise memory compare. This is because a domainname is a fixed size structure holding variable-length data.
+ // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that
+ // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ.
+ if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0) // Used in update packets to mean "Delete An RRset" (RFC 2136)
+ rr->resrec.rdlength = 0;
+ else switch (rr->resrec.rrtype)
{
- case kDNSType_A: rr->resrec.rdata->u.ipv4.b[0] = ptr[0];
+ case kDNSType_A: if (pktrdlength != sizeof(mDNSv4Addr)) return(mDNSNULL);
+ rr->resrec.rdata->u.ipv4.b[0] = ptr[0];
rr->resrec.rdata->u.ipv4.b[1] = ptr[1];
rr->resrec.rdata->u.ipv4.b[2] = ptr[2];
rr->resrec.rdata->u.ipv4.b[3] = ptr[3];
break;
- case kDNSType_CNAME:// Same as PTR
case kDNSType_NS:
- case kDNSType_PTR: if (!getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name))
- { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
+ case kDNSType_CNAME:
+ case kDNSType_PTR:
+ case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name);
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
//debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength);
break;
- case kDNSType_NULL: //Same as TXT
- case kDNSType_HINFO://Same as TXT
- case kDNSType_TXT: if (pktrdlength > rr->resrec.rdata->MaxRDLength)
+ case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname);
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
+ ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname);
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; }
+ if (ptr + 0x14 != end) { debugf("GetLargeResourceRecord: Malformed SOA RDATA"); return mDNSNULL; }
+ rr->resrec.rdata->u.soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
+ rr->resrec.rdata->u.soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
+ rr->resrec.rdata->u.soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
+ rr->resrec.rdata->u.soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
+ rr->resrec.rdata->u.soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
+ break;
+
+ case kDNSType_NULL:
+ case kDNSType_HINFO:
+ case kDNSType_TSIG:
+ case kDNSType_TXT:
+ case kDNSType_X25:
+ case kDNSType_ISDN:
+ case kDNSType_LOC:
+ case kDNSType_DHCID:if (pktrdlength > rr->resrec.rdata->MaxRDLength)
{
- debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)",
+ debugf("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)",
DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
return(mDNSNULL);
}
rr->resrec.rdlength = pktrdlength;
- mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
+ mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength);
break;
- case kDNSType_AAAA: mDNSPlatformMemCopy(ptr, &rr->resrec.rdata->u.ipv6, sizeof(rr->resrec.rdata->u.ipv6));
+ case kDNSType_MX:
+ case kDNSType_AFSDB:
+ case kDNSType_RT:
+ case kDNSType_KX: if (pktrdlength < 3) return(mDNSNULL); // Preference + domainname
+ rr->resrec.rdata->u.mx.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+ ptr = getDomainName(msg, ptr+2, end, &rr->resrec.rdata->u.mx.exchange);
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed MX name"); return(mDNSNULL); }
+ //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
+ break;
+
+ case kDNSType_RP: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.mbox); // Domainname + domainname
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed RP mbox"); return mDNSNULL; }
+ ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.txt);
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed RP txt"); return mDNSNULL; }
+ break;
+
+ case kDNSType_PX: if (pktrdlength < 4) return(mDNSNULL); // Preference + domainname + domainname
+ rr->resrec.rdata->u.px.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+ ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.px.map822);
+ if (!ptr) { debugf("GetLargeResourceRecord: Malformed PX map822"); return mDNSNULL; }
+ ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.px.mapx400);
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); return mDNSNULL; }
break;
- case kDNSType_SRV: rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+ case kDNSType_AAAA: if (pktrdlength != sizeof(mDNSv6Addr)) return(mDNSNULL);
+ mDNSPlatformMemCopy(&rr->resrec.rdata->u.ipv6, ptr, sizeof(rr->resrec.rdata->u.ipv6));
+ break;
+
+ case kDNSType_SRV: if (pktrdlength < 7) return(mDNSNULL); // Priority + weight + port + domainname
+ rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
rr->resrec.rdata->u.srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
rr->resrec.rdata->u.srv.port.b[0] = ptr[4];
rr->resrec.rdata->u.srv.port.b[1] = ptr[5];
- if (!getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target))
- { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
+ ptr = getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target);
+ if (ptr != end) { debugf("GetLargeResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength);
break;
- case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname);
- if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
- ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname);
- if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; }
- if (ptr + 0x14 != end) { debugf("GetResourceRecord: Malformed SOA RDATA"); return mDNSNULL; }
- rr->resrec.rdata->u.soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
- rr->resrec.rdata->u.soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
- rr->resrec.rdata->u.soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
- rr->resrec.rdata->u.soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
- rr->resrec.rdata->u.soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
- break;
-
- case kDNSType_OPT: getOptRdata(ptr, end, largecr, pktrdlength); break;
+ case kDNSType_OPT: ptr = getOptRdata(ptr, end, largecr, pktrdlength); break;
+ if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed OptRdata"); return(mDNSNULL); }
default: if (pktrdlength > rr->resrec.rdata->MaxRDLength)
{
- debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
+ debugf("GetLargeResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
return(mDNSNULL);
}
- debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
+ debugf("GetLargeResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
// Note: Just because we don't understand the record type, that doesn't
// mean we fail. The DNS protocol specifies rdlength, so we can
// We also grab a binary copy of the rdata anyway, since the caller
// might know how to interpret it even if we don't.
rr->resrec.rdlength = pktrdlength;
- mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength);
+ mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength);
break;
}
rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
- SetNewRData(&rr->resrec, mDNSNULL, 0);
+ SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rdlength, rdestimate, rdatahash for us
// Success! Now fill in RecordType to show this record contains valid data
rr->resrec.RecordType = RecordType;
- return(ptr + pktrdlength);
+ return(end);
}
mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
DNSQuestion *question)
{
+ mDNSPlatformMemZero(question, sizeof(*question));
question->InterfaceID = InterfaceID;
ptr = getDomainName(msg, ptr, end, &question->qname);
if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
return (ptr);
}
+mDNSexport const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDNSu8 *const end)
+ {
+ int i;
+ const mDNSu8 *ptr = LocateAdditionals(msg, end);
+
+ // Locate the OPT record.
+ // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
+ // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
+ // but not necessarily the *last* entry in the Additional Section.
+ for (i = 0; ptr && i < msg->h.numAdditionals; i++)
+ {
+ if (ptr + 10 + LLQ_OPT_RDLEN <= end && // Make sure we have 10+22 bytes of data
+ ptr[0] == 0 && // Name must be root label
+ ptr[1] == (kDNSType_OPT >> 8 ) && // rrtype OPT
+ ptr[2] == (kDNSType_OPT & 0xFF) &&
+ ((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)LLQ_OPT_RDLEN)
+ return(ptr);
+ else
+ ptr = skipResourceRecord(msg, ptr, end);
+ }
+ return(mDNSNULL);
+ }
+
+// On success, GetLLQOptData returns pointer to storage within shared "m->rec";
+// it is callers responsibilty to clear m->rec.r.resrec.RecordType after use
+// Note: An OPT RDataBody actually contains one or more variable-length rdataOPT objects packed together
+// The code that currently calls this assumes there's only one, instead of iterating through the set
+mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end)
+ {
+ const mDNSu8 *ptr = LocateLLQOptData(msg, end);
+ if (ptr)
+ {
+ ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
+ if (ptr) return(&m->rec.r.resrec.rdata->u.opt);
+ }
+ return(mDNSNULL);
+ }
+
+mDNSexport const mDNSu8 *LocateLeaseOptData(const DNSMessage *const msg, const mDNSu8 *const end)
+ {
+ int i;
+ const mDNSu8 *ptr = LocateAdditionals(msg, end);
+
+ // Locate the OPT record.
+ // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
+ // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
+ // but not necessarily the *last* entry in the Additional Section.
+ for (i = 0; ptr && i < msg->h.numAdditionals; i++)
+ {
+ if (ptr + 10 + LEASE_OPT_RDLEN <= end && // Make sure we have 10+8 bytes of data
+ ptr[0] == 0 && // Name must be root label
+ ptr[1] == (kDNSType_OPT >> 8 ) && // rrtype OPT
+ ptr[2] == (kDNSType_OPT & 0xFF) &&
+ ((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)LEASE_OPT_RDLEN)
+ return(ptr);
+ else
+ ptr = skipResourceRecord(msg, ptr, end);
+ }
+ return(mDNSNULL);
+ }
+
+// Get the lease life of records in a dynamic update
+// returns 0 on error or if no lease present
+mDNSexport mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end)
+ {
+ mDNSu32 result = 0;
+ const mDNSu8 *ptr = LocateLeaseOptData(msg, end);
+ if (ptr) ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
+ if (ptr && m->rec.r.resrec.rdlength >= LEASE_OPT_RDLEN && m->rec.r.resrec.rdata->u.opt.opt == kDNSOpt_Lease)
+ result = m->rec.r.resrec.rdata->u.opt.OptData.updatelease;
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ return(result);
+ }
+
+mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label)
+ {
+ int i;
+ LogMsg("%2d %s", count, label);
+ for (i = 0; i < count && ptr; i++)
+ {
+ // This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage,
+ // but since it's only used for debugging (and probably only on OS X, not on
+ // embedded systems) putting a 9kB object on the stack isn't a big problem.
+ LargeCacheRecord largecr;
+ ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr);
+ if (ptr) LogMsg("%2d TTL%7d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
+ }
+ if (!ptr) LogMsg("ERROR: Premature end of packet data");
+ return(ptr);
+ }
+
+#define DNS_OP_Name(X) ( \
+ (X) == kDNSFlag0_OP_StdQuery ? "" : \
+ (X) == kDNSFlag0_OP_Iquery ? "Iquery " : \
+ (X) == kDNSFlag0_OP_Status ? "Status " : \
+ (X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \
+ (X) == kDNSFlag0_OP_Notify ? "Notify " : \
+ (X) == kDNSFlag0_OP_Update ? "Update " : "?? " )
+
+#define DNS_RC_Name(X) ( \
+ (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \
+ (X) == kDNSFlag1_RC_FmtErr ? "FmtErr" : \
+ (X) == kDNSFlag1_RC_SrvErr ? "SrvErr" : \
+ (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" : \
+ (X) == kDNSFlag1_RC_NotImpl ? "NotImpl" : \
+ (X) == kDNSFlag1_RC_Refused ? "Refused" : \
+ (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \
+ (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \
+ (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \
+ (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \
+ (X) == kDNSFlag1_RC_NotZone ? "NotZone" : "??" )
+
+// Note: DumpPacket expects the packet header fields in host byte order, not network byte order
+mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport, const mDNSAddr *addr, mDNSIPPort port, const DNSMessage *const msg, const mDNSu8 *const end)
+ {
+ mDNSBool IsUpdate = ((msg->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update);
+ const mDNSu8 *ptr = msg->data;
+ int i;
+ DNSQuestion q;
+
+ LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes %s %#a:%d%s --",
+ sent ? "Sent" : "Received", transport,
+ DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
+ msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query",
+ msg->h.flags.b[0], msg->h.flags.b[1],
+ DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
+ msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
+ msg->h.flags.b[0] & kDNSFlag0_AA ? "AA " : "",
+ msg->h.flags.b[0] & kDNSFlag0_TC ? "TC " : "",
+ msg->h.flags.b[0] & kDNSFlag0_RD ? "RD " : "",
+ msg->h.flags.b[1] & kDNSFlag1_RA ? "RA " : "",
+ msg->h.flags.b[1] & kDNSFlag1_AD ? "AD " : "",
+ msg->h.flags.b[1] & kDNSFlag1_CD ? "CD " : "",
+ mDNSVal16(msg->h.id),
+ end - msg->data,
+ sent ? "to" : "from", addr, mDNSVal16(port),
+ (msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : ""
+ );
+
+ LogMsg("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions");
+ for (i = 0; i < msg->h.numQuestions && ptr; i++)
+ {
+ ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
+ if (ptr) LogMsg("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype));
+ }
+ ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers, IsUpdate ? "Prerequisites" : "Answers");
+ ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates" : "Authorities");
+ ptr = DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals");
+ LogMsg("--------------");
+ }
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
-#pragma mark -
#pragma mark - Packet Sending Functions
#endif
-mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
- mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo)
+// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
+struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
+
+mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
+ mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo)
{
mStatus status;
- int nsent;
- mDNSs32 msglen;
+ long nsent;
+ unsigned long msglen;
mDNSu8 lenbuf[2];
mDNSu16 numQuestions = msg->h.numQuestions;
mDNSu16 numAnswers = msg->h.numAnswers;
if (authInfo)
{
- end = DNSDigest_SignMessage(msg, &end, &numAdditionals, authInfo);
+ end = DNSDigest_SignMessage(msg, &end, authInfo, 0);
if (!end) return mStatus_UnknownErr;
}
// Send the packet on the wire
-
- if (sd >= 0)
+ if (sock)
{
msglen = (mDNSu16)(end - (mDNSu8 *)msg);
lenbuf[0] = (mDNSu8)(msglen >> 8); // host->network byte conversion
lenbuf[1] = (mDNSu8)(msglen & 0xFF);
- nsent = mDNSPlatformWriteTCP(sd, (char*)lenbuf, 2);
+
+ nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);
//!!!KRS make sure kernel is sending these as 1 packet!
if (nsent != 2) goto tcp_error;
- nsent = mDNSPlatformWriteTCP(sd, (char *)msg, msglen);
- if (nsent != msglen) goto tcp_error;
+
+ nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
+ if (nsent != (long)msglen) goto tcp_error;
status = mStatus_NoError;
}
else
msg->h.numQuestions = numQuestions;
msg->h.numAnswers = numAnswers;
msg->h.numAuthorities = numAuthorities;
- msg->h.numAdditionals = (mDNSu16)(authInfo ? numAdditionals - 1 : numAdditionals);
+ msg->h.numAdditionals = numAdditionals;
+
+ if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG && !mDNSOpaque16IsZero(msg->h.id))
+ {
+ if (authInfo) msg->h.numAdditionals++; // Want to include TSIG in DumpPacket output
+ DumpPacket(m, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", dst, dstport, msg, end);
+ if (authInfo) msg->h.numAdditionals--;
+ }
return(status);
#pragma mark - RR List Management & Task Management
#endif
-mDNSexport void mDNS_Lock(mDNS *const m)
+mDNSexport void mDNS_Lock_(mDNS *const m)
{
// MUST grab the platform lock FIRST!
mDNSPlatformLock(m);
// However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
// If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
// If mDNS_busy != mDNS_reentrancy that's a bad sign
+#if ForceAlerts
if (m->mDNS_busy != m->mDNS_reentrancy)
+ {
LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+ *(long*)0 = 0;
+ }
+#endif
// If this is an initial entry into the mDNSCore code, set m->timenow
// else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
if (m->SuppressSending) return(m->SuppressSending);
#ifndef UNICAST_DISABLED
- if (e - m->uDNS_info.nextevent > 0) e = m->uDNS_info.nextevent;
+ if (e - m->NextuDNSEvent > 0) e = m->NextuDNSEvent;
#endif
if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck;
if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery;
if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe;
if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
+ if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp;
return(e);
}
-mDNSexport void mDNS_Unlock(mDNS *const m)
+mDNSexport void mDNS_Unlock_(mDNS *const m)
{
// Decrement mDNS_busy
m->mDNS_busy--;
// Check for locking failures
+#if ForceAlerts
if (m->mDNS_busy != m->mDNS_reentrancy)
+ {
LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+ *(long*)0 = 0;
+ }
+#endif
// If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
if (m->mDNS_busy == 0)
// MUST release the platform lock LAST!
mDNSPlatformUnlock(m);
}
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Specialized mDNS version of vsnprintf
+#endif
+
+static const struct mDNSprintf_format
+ {
+ unsigned leftJustify : 1;
+ unsigned forceSign : 1;
+ unsigned zeroPad : 1;
+ unsigned havePrecision : 1;
+ unsigned hSize : 1;
+ unsigned lSize : 1;
+ char altForm;
+ char sign; // +, - or space
+ unsigned int fieldWidth;
+ unsigned int precision;
+ } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
+ {
+ mDNSu32 nwritten = 0;
+ int c;
+ if (buflen == 0) return(0);
+ buflen--; // Pre-reserve one space in the buffer for the terminating null
+ if (buflen == 0) goto exit;
+
+ for (c = *fmt; c != 0; c = *++fmt)
+ {
+ if (c != '%')
+ {
+ *sbuffer++ = (char)c;
+ if (++nwritten >= buflen) goto exit;
+ }
+ else
+ {
+ unsigned int i=0, j;
+ // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
+ // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
+ // The size needs to be enough for a 256-byte domain name plus some error text.
+ #define mDNS_VACB_Size 300
+ char mDNS_VACB[mDNS_VACB_Size];
+ #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
+ #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
+ char *s = mDNS_VACB_Lim, *digits;
+ struct mDNSprintf_format F = mDNSprintf_format_default;
+
+ while (1) // decode flags
+ {
+ c = *++fmt;
+ if (c == '-') F.leftJustify = 1;
+ else if (c == '+') F.forceSign = 1;
+ else if (c == ' ') F.sign = ' ';
+ else if (c == '#') F.altForm++;
+ else if (c == '0') F.zeroPad = 1;
+ else break;
+ }
+
+ if (c == '*') // decode field width
+ {
+ int f = va_arg(arg, int);
+ if (f < 0) { f = -f; F.leftJustify = 1; }
+ F.fieldWidth = (unsigned int)f;
+ c = *++fmt;
+ }
+ else
+ {
+ for (; c >= '0' && c <= '9'; c = *++fmt)
+ F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
+ }
+
+ if (c == '.') // decode precision
+ {
+ if ((c = *++fmt) == '*')
+ { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
+ else for (; c >= '0' && c <= '9'; c = *++fmt)
+ F.precision = (10 * F.precision) + (c - '0');
+ F.havePrecision = 1;
+ }
+
+ if (F.leftJustify) F.zeroPad = 0;
+
+ conv:
+ switch (c) // perform appropriate conversion
+ {
+ unsigned long n;
+ case 'h' : F.hSize = 1; c = *++fmt; goto conv;
+ case 'l' : // fall through
+ case 'L' : F.lSize = 1; c = *++fmt; goto conv;
+ case 'd' :
+ case 'i' : if (F.lSize) n = (unsigned long)va_arg(arg, long);
+ else n = (unsigned long)va_arg(arg, int);
+ if (F.hSize) n = (short) n;
+ if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
+ else if (F.forceSign) F.sign = '+';
+ goto decimal;
+ case 'u' : if (F.lSize) n = va_arg(arg, unsigned long);
+ else n = va_arg(arg, unsigned int);
+ if (F.hSize) n = (unsigned short) n;
+ F.sign = 0;
+ goto decimal;
+ decimal: if (!F.havePrecision)
+ {
+ if (F.zeroPad)
+ {
+ F.precision = F.fieldWidth;
+ if (F.sign) --F.precision;
+ }
+ if (F.precision < 1) F.precision = 1;
+ }
+ if (F.precision > mDNS_VACB_Size - 1)
+ F.precision = mDNS_VACB_Size - 1;
+ for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
+ for (; i < F.precision; i++) *--s = '0';
+ if (F.sign) { *--s = F.sign; i++; }
+ break;
+
+ case 'o' : if (F.lSize) n = va_arg(arg, unsigned long);
+ else n = va_arg(arg, unsigned int);
+ if (F.hSize) n = (unsigned short) n;
+ if (!F.havePrecision)
+ {
+ if (F.zeroPad) F.precision = F.fieldWidth;
+ if (F.precision < 1) F.precision = 1;
+ }
+ if (F.precision > mDNS_VACB_Size - 1)
+ F.precision = mDNS_VACB_Size - 1;
+ for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
+ if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
+ for (; i < F.precision; i++) *--s = '0';
+ break;
+
+ case 'a' : {
+ unsigned char *a = va_arg(arg, unsigned char *);
+ if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ else
+ {
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ if (F.altForm)
+ {
+ mDNSAddr *ip = (mDNSAddr*)a;
+ switch (ip->type)
+ {
+ case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break;
+ case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
+ default: F.precision = 0; break;
+ }
+ }
+ if (F.altForm && !F.precision)
+ i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "«ZERO ADDRESS»");
+ else switch (F.precision)
+ {
+ case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
+ a[0], a[1], a[2], a[3]); break;
+ case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
+ a[0], a[1], a[2], a[3], a[4], a[5]); break;
+ case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
+ "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+ a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
+ a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
+ default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
+ " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
+ }
+ }
+ }
+ break;
+
+ case 'p' : F.havePrecision = F.lSize = 1;
+ F.precision = 8;
+ case 'X' : digits = "0123456789ABCDEF";
+ goto hexadecimal;
+ case 'x' : digits = "0123456789abcdef";
+ hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
+ else n = va_arg(arg, unsigned int);
+ if (F.hSize) n = (unsigned short) n;
+ if (!F.havePrecision)
+ {
+ if (F.zeroPad)
+ {
+ F.precision = F.fieldWidth;
+ if (F.altForm) F.precision -= 2;
+ }
+ if (F.precision < 1) F.precision = 1;
+ }
+ if (F.precision > mDNS_VACB_Size - 1)
+ F.precision = mDNS_VACB_Size - 1;
+ for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
+ for (; i < F.precision; i++) *--s = '0';
+ if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
+ break;
+
+ case 'c' : *--s = (char)va_arg(arg, int); i = 1; break;
+
+ case 's' : s = va_arg(arg, char *);
+ if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ else switch (F.altForm)
+ {
+ case 0: i=0;
+ if (!F.havePrecision) // C string
+ while (s[i]) i++;
+ else
+ {
+ while ((i < F.precision) && s[i]) i++;
+ // Make sure we don't truncate in the middle of a UTF-8 character
+ // If last character we got was any kind of UTF-8 multi-byte character,
+ // then see if we have to back up.
+ // This is not as easy as the similar checks below, because
+ // here we can't assume it's safe to examine the *next* byte, so we
+ // have to confine ourselves to working only backwards in the string.
+ j = i; // Record where we got to
+ // Now, back up until we find first non-continuation-char
+ while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
+ // Now s[i-1] is the first non-continuation-char
+ // and (j-i) is the number of continuation-chars we found
+ if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char
+ {
+ i--; // Tentatively eliminate this start-char as well
+ // Now (j-i) is the number of characters we're considering eliminating.
+ // To be legal UTF-8, the start-char must contain (j-i) one-bits,
+ // followed by a zero bit. If we shift it right by (7-(j-i)) bits
+ // (with sign extension) then the result has to be 0xFE.
+ // If this is right, then we reinstate the tentatively eliminated bytes.
+ if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
+ }
+ }
+ break;
+ case 1: i = (unsigned char) *s++; break; // Pascal string
+ case 2: { // DNS label-sequence name
+ unsigned char *a = (unsigned char *)s;
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ if (*a == 0) *s++ = '.'; // Special case for root DNS name
+ while (*a)
+ {
+ char buf[63*4+1];
+ if (*a > 63)
+ { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
+ if (s + *a >= &mDNS_VACB[254])
+ { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
+ // Need to use ConvertDomainLabelToCString to do proper escaping here,
+ // so it's clear what's a literal dot and what's a label separator
+ ConvertDomainLabelToCString((domainlabel*)a, buf);
+ s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%s.", buf);
+ a += 1 + *a;
+ }
+ i = (mDNSu32)(s - mDNS_VACB);
+ s = mDNS_VACB; // Reset s back to the start of the buffer
+ break;
+ }
+ }
+ // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
+ if (F.havePrecision && i > F.precision)
+ { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+ break;
+
+ case 'n' : s = va_arg(arg, char *);
+ if (F.hSize) * (short *) s = (short)nwritten;
+ else if (F.lSize) * (long *) s = (long)nwritten;
+ else * (int *) s = (int)nwritten;
+ continue;
+
+ default: s = mDNS_VACB;
+ i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
+
+ case '%' : *sbuffer++ = (char)c;
+ if (++nwritten >= buflen) goto exit;
+ break;
+ }
+
+ if (i < F.fieldWidth && !F.leftJustify) // Pad on the left
+ do {
+ *sbuffer++ = ' ';
+ if (++nwritten >= buflen) goto exit;
+ } while (i < --F.fieldWidth);
+
+ // Make sure we don't truncate in the middle of a UTF-8 character.
+ // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
+ // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
+ // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
+ // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
+ if (i > buflen - nwritten)
+ { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+ for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result
+ nwritten += i;
+ if (nwritten >= buflen) goto exit;
+
+ for (; i < F.fieldWidth; i++) // Pad on the right
+ {
+ *sbuffer++ = ' ';
+ if (++nwritten >= buflen) goto exit;
+ }
+ }
+ }
+ exit:
+ *sbuffer++ = 0;
+ return(nwritten);
+ }
+
+mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
+ {
+ mDNSu32 length;
+
+ va_list ptr;
+ va_start(ptr,fmt);
+ length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
+ va_end(ptr);
+
+ return(length);
+ }
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSCommon.h,v $
-Revision 1.33 2006/03/10 21:51:41 cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Split out SameRDataBody() into a separate routine so it can be called from other code
-
-Revision 1.32 2005/03/21 00:33:51 shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
-
-Revision 1.31 2005/02/18 00:43:11 cheshire
-<rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
-
-Revision 1.30 2005/01/19 03:12:44 cheshire
-Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
-
-Revision 1.29 2004/12/15 02:11:22 ksekar
-<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
-
-Revision 1.28 2004/12/06 21:15:22 ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.27 2004/12/03 07:20:50 ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
-
-Revision 1.26 2004/12/03 05:18:33 ksekar
-<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
-
-Revision 1.25 2004/10/26 03:52:02 cheshire
-Update checkin comments
-
-Revision 1.24 2004/10/23 01:16:00 cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
-
-Revision 1.23 2004/10/03 23:18:58 cheshire
-Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h
+Revision 1.54 2007/10/05 17:56:10 cheshire
+Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
-Revision 1.22 2004/09/30 00:24:56 ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.53 2007/09/27 17:42:49 cheshire
+Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
-Revision 1.21 2004/09/17 01:08:48 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.52 2007/09/26 00:49:46 cheshire
+Improve packet logging to show sent and received packets,
+transport protocol (UDP/TCP/TLS) and source/destination address:port
-Revision 1.20 2004/09/17 00:49:51 cheshire
-Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use
-is GetLargeResourceRecord
+Revision 1.51 2007/09/21 21:12:36 cheshire
+<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
-Revision 1.19 2004/09/16 21:59:15 cheshire
-For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+Revision 1.50 2007/09/20 01:12:06 cheshire
+Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
-Revision 1.18 2004/09/16 02:29:39 cheshire
-Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
-uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
+Revision 1.49 2007/08/30 00:31:20 cheshire
+Improve "locking failure" debugging messages to show function name using __func__ macro
-Revision 1.17 2004/09/14 23:27:46 cheshire
-Fix compile errors
+Revision 1.48 2007/05/25 00:25:44 cheshire
+<rdar://problem/5227737> Need to enhance putRData to output all current known types
-Revision 1.16 2004/08/13 23:46:58 cheshire
-"asyncronous" -> "asynchronous"
+Revision 1.47 2007/05/01 21:46:31 cheshire
+Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
-Revision 1.15 2004/08/10 23:19:14 ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
+Revision 1.46 2007/04/22 20:18:10 cheshire
+Add comment about mDNSRandom()
-Revision 1.14 2004/05/28 23:42:36 ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.45 2007/04/22 06:02:02 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.13 2004/05/18 23:51:25 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.44 2007/03/28 01:20:05 cheshire
+<rdar://problem/4883206> Improve/create logging for secure browse
-Revision 1.12 2004/04/22 04:03:59 cheshire
-Headers should use "extern" declarations, not "mDNSexport"
+Revision 1.43 2007/03/20 17:07:15 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-Revision 1.11 2004/04/14 23:09:28 ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.42 2007/03/10 03:26:44 cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Revision 1.10 2004/03/13 01:57:33 ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.41 2007/01/18 23:18:17 cheshire
+Source code tidying: Delete extraneous white space
-Revision 1.9 2004/02/21 08:56:58 bradley
-Wrap prototypes with extern "C" for C++ builds.
+Revision 1.40 2007/01/05 08:30:40 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.8 2004/02/06 23:04:18 ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.39 2007/01/04 21:45:20 cheshire
+Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
+to do additional lock sanity checking around callback invocations
-Revision 1.7 2004/02/03 19:47:36 ksekar
-Added an asynchronous state machine mechanism to uDNS.c, including
-calls to find the parent zone for a domain name. Changes include code
-in repository previously dissabled via "#if 0 incomplete". Codepath
-is currently unused, and will be called to create update records, etc.
+Revision 1.38 2006/12/22 20:59:49 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.6 2004/01/27 20:15:22 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.37 2006/08/14 23:24:22 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.5 2004/01/24 03:40:56 cheshire
-Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.h so embedded clients can use it
+Revision 1.36 2006/07/05 22:56:07 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-Revision 1.4 2004/01/24 03:38:27 cheshire
-Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+Revision 1.35 2006/06/29 07:42:14 cheshire
+<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-Revision 1.3 2004/01/23 23:23:14 ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.34 2006/03/18 21:47:56 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-Revision 1.2 2004/01/21 21:12:23 cheshire
-Add missing newline at end of file to make Unix tools happier
-
-Revision 1.1 2003/12/13 03:05:27 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.33 2006/03/10 21:51:41 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Split out SameRDataBody() into a separate routine so it can be called from other code
-
- */
+*/
#ifndef __DNSCOMMON_H_
#define __DNSCOMMON_H_
kDNSFlag0_QR_Mask = 0x80, // Query or response?
kDNSFlag0_QR_Query = 0x00,
kDNSFlag0_QR_Response = 0x80,
-
+
kDNSFlag0_OP_Mask = 0x78, // Operation type
kDNSFlag0_OP_StdQuery = 0x00,
kDNSFlag0_OP_Iquery = 0x08,
kDNSFlag0_OP_Unused3 = 0x18,
kDNSFlag0_OP_Notify = 0x20,
kDNSFlag0_OP_Update = 0x28,
-
+
kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
-
+
kDNSFlag0_AA = 0x04, // Authoritative Answer?
kDNSFlag0_TC = 0x02, // Truncated?
kDNSFlag0_RD = 0x01, // Recursion Desired?
kDNSFlag1_RA = 0x80, // Recursion Available?
-
+
kDNSFlag1_Zero = 0x40, // Reserved; must be zero
kDNSFlag1_AD = 0x20, // Authentic Data [RFC 2535]
kDNSFlag1_CD = 0x10, // Checking Disabled [RFC 2535]
- kDNSFlag1_RC = 0x0F, // Response code
+ kDNSFlag1_RC_Mask = 0x0F, // Response code
kDNSFlag1_RC_NoErr = 0x00,
kDNSFlag1_RC_FmtErr = 0x01,
kDNSFlag1_RC_SrvErr = 0x02,
TSIG_ErrBadKey = 17,
TSIG_ErrBadTime = 18
} TSIG_ErrorCode;
-
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
extern const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf);
extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf);
-extern mDNSu32 mDNSRandom(mDNSu32 max);
-
+extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from zero to max inclusive
+extern mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#pragma mark - Domain Name Utility Functions
#endif
-
+
#define mdnsIsDigit(X) ((X) >= '0' && (X) <= '9')
#define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z')
#define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z')
#define mdnsIsLetter(X) (mDNSIsUpperCase(X) || mDNSIsLowerCase(X))
-
+
#define mdnsValidHostChar(X, notfirst, notlast) (mdnsIsLetter(X) || mdnsIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') )
extern mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent);
+extern int CountLabels(const domainname *d);
+extern const domainname *SkipLeadingLabels(const domainname *d, int skip);
extern mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max);
extern mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText);
extern mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText);
extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText);
-extern void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
#define ValidateDomainName(N) (DomainNameLength(N) <= MAX_DOMAIN_NAME)
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#endif
extern mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb);
-
extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2);
extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2);
-
extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-
+extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2);
-
extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
+extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
#define GetRRDomainNameTarget(RR) ( \
((RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_NS) \
? &(RR)->rdata->u.name : \
((RR)->rrtype == kDNSType_SRV ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
-extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
#define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique && (X)->resrec.RecordType != kDNSRecordTypeDeregistering)
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
-#pragma mark -
#pragma mark - DNS Message Creation Functions
#endif
extern void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags);
extern const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname);
-
extern mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name);
-
-extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr);
+extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr);
// If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes,
-// but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet
-
+// but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet
extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit);
-
#define PutResourceRecordTTL(msg, ptr, count, rr, ttl) PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \
((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? (msg)->data + NormalMaxDNSMessageData : (msg)->data + AbsoluteMaxDNSMessageData)
-
#define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \
(msg)->data + AbsoluteMaxDNSMessageData)
-
extern mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 maxttl);
-
extern mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr);
extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass);
-
extern mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass);
-
-extern mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end);
-
+extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end);
extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr);
-
extern mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype);
-
extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name);
-
extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease);
-
#define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl)
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#pragma mark - DNS Message Parsing Functions
#endif
+#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
extern mDNSu32 DomainNameHashValue(const domainname *const name);
-
extern void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength);
-
-
extern const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end);
-
extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
domainname *const name);
-
extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
-
-extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
+extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr);
-
extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
-
extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
DNSQuestion *question);
-
extern const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end);
-
extern const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end);
-
extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end);
+extern const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDNSu8 *const end);
+extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end);
+extern const mDNSu8 *LocateLeaseOptData(const DNSMessage *const msg, const mDNSu8 *const end);
+extern mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end);
+extern void DumpPacket(mDNS *const m, mDNSBool sent, char *type, const mDNSAddr *addr, mDNSIPPort port, const DNSMessage *const msg, const mDNSu8 *const end);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
-#pragma mark -
#pragma mark - Packet Sending Functions
#endif
-extern mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
- mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo);
+extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
+ mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - RR List Management & Task Management
#endif
-extern void mDNS_Lock(mDNS *const m);
-extern void mDNS_Unlock(mDNS *const m);
+extern void mDNS_Lock_(mDNS *const m);
+extern void mDNS_Unlock_(mDNS *const m);
+
+#define mDNS_Lock(X) do { \
+ if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Lock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \
+ mDNS_Lock_(X); } while (0)
+
+#define mDNS_Unlock(X) do { mDNS_Unlock_(X); \
+ if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Unlock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \
+ } while (0)
+
+#define mDNS_DropLockBeforeCallback() do { m->mDNS_reentrancy++; \
+ if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Locking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
+ } while (0)
+
+#define mDNS_ReclaimLockAfterCallback() do { \
+ if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Unlocking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
+ m->mDNS_reentrancy--; } while (0)
#ifdef __cplusplus
}
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSDigest.c,v $
+Revision 1.23 2007/09/21 21:12:36 cheshire
+DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
+
+Revision 1.22 2007/04/22 06:02:02 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
+
+Revision 1.21 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
+
+Revision 1.20 2006/12/22 20:59:49 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.19 2006/12/21 00:06:07 cheshire
+Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
+
+Revision 1.18 2006/12/19 22:41:21 cheshire
+Fix compiler warnings
+
+Revision 1.17 2006/08/14 23:24:22 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.16 2006/07/05 23:05:15 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Add DNSDigest_VerifyMessage() function
+
+Revision 1.15 2006/06/20 04:12:30 cheshire
+<rdar://problem/4490961> DNS Update broken
+
+Revision 1.14 2006/02/25 23:12:07 cheshire
+<rdar://problem/4427969> Fix to avoid code generation warning/error on FreeBSD 7
+
Revision 1.13 2004/12/16 20:12:59 cheshire
<rdar://problem/3324626> Cache memory management improvements
#pragma warning(disable:4127)
#endif
+
+ // ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Byte Swapping Functions
+#endif
+
+mDNSlocal mDNSu16 NToH16(mDNSu8 * bytes)
+ {
+ return (mDNSu16)((mDNSu16)bytes[0] << 8 | (mDNSu16)bytes[1]);
+ }
+
+mDNSlocal mDNSu32 NToH32(mDNSu8 * bytes)
+ {
+ return (mDNSu32)((mDNSu32) bytes[0] << 24 | (mDNSu32) bytes[1] << 16 | (mDNSu32) bytes[2] << 8 | (mDNSu32)bytes[3]);
+ }
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - MD5 Hash Functions
# define ROTATE(a,n) (unsigned MD32_REG_T)__rlwinm((int)a,n,0,31)
# elif defined(__MC68K__)
/* Motorola specific tweak. <appro@fy.chalmers.se> */
-# define ROTATE(a,n) ( n<24 ? __rol(a,n) : __ror(a,32-n) )
+# define ROTATE(a,n) (n<24 ? __rol(a,n) : __ror(a,32-n))
# else
# define ROTATE(a,n) __rol(a,n)
# endif
#endif
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - base64 -> binary conversion
#endif
-static const char Base64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
#define mDNSisspace(x) (x == '\t' || x == '\n' || x == '\v' || x == '\f' || x == '\r' || x == ' ')
-static const char *mDNSstrchr(const char *s, int c)
+mDNSlocal const char *mDNSstrchr(const char *s, int c)
{
while (1)
{
// it returns the number of data bytes stored at the target, or -1 on error.
// adapted from BIND sources
-mDNSexport mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize)
+mDNSlocal mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize)
{
int tarindex, state, ch;
const char *pos;
#define HMAC_MD5_AlgName (*(const domainname*) "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int")
// Adapted from Appendix, RFC 2104
-mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len)
+mDNSlocal void DNSDigest_ConstructHMACKey(DomainAuthInfo *info, const mDNSu8 *key, mDNSu32 len)
{
MD5_CTX k;
mDNSu8 buf[MD5_LEN];
}
// store key in pads
- mDNSPlatformMemZero(info->key.ipad, HMAC_LEN);
- mDNSPlatformMemZero(info->key.opad, HMAC_LEN);
- mDNSPlatformMemCopy(key, info->key.ipad, len);
- mDNSPlatformMemCopy(key, info->key.opad, len);
+ mDNSPlatformMemZero(info->keydata_ipad, HMAC_LEN);
+ mDNSPlatformMemZero(info->keydata_opad, HMAC_LEN);
+ mDNSPlatformMemCopy(info->keydata_ipad, key, len);
+ mDNSPlatformMemCopy(info->keydata_opad, key, len);
// XOR key with ipad and opad values
for (i = 0; i < HMAC_LEN; i++)
{
- info->key.ipad[i] ^= HMAC_IPAD;
- info->key.opad[i] ^= HMAC_OPAD;
+ info->keydata_ipad[i] ^= HMAC_IPAD;
+ info->keydata_opad[i] ^= HMAC_OPAD;
}
}
-mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info)
+mDNSexport mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key)
+ {
+ mDNSu8 keybuf[1024];
+ mDNSs32 keylen = DNSDigest_Base64ToBin(b64key, keybuf, sizeof(keybuf));
+ if (keylen < 0) return(keylen);
+ DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
+ return(keylen);
+ }
+
+mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode)
{
AuthRecord tsig;
- mDNSu8 *countPtr, *rdata;
+ mDNSu8 *rdata, *const countPtr = (mDNSu8 *)&msg->h.numAdditionals; // Get existing numAdditionals value
mDNSu32 utc32;
mDNSu8 utc48[6];
mDNSu8 digest[MD5_LEN];
mDNSu32 len;
mDNSOpaque16 buf;
MD5_CTX c;
+ mDNSu16 numAdditionals = (mDNSu16)((mDNSu16)countPtr[0] << 8 | countPtr[1]);
// Init MD5 context, digest inner key pad and message
MD5_Init(&c);
- MD5_Update(&c, info->key.ipad, HMAC_LEN);
+ MD5_Update(&c, info->keydata_ipad, HMAC_LEN);
MD5_Update(&c, (mDNSu8 *)msg, (unsigned long)(*end - (mDNSu8 *)msg));
// Construct TSIG RR, digesting variables as apporpriate
- mDNSPlatformMemZero(&tsig, sizeof(AuthRecord));
mDNS_SetupResourceRecord(&tsig, mDNSNULL, 0, kDNSType_TSIG, 0, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
// key name
- AssignDomainName(tsig.resrec.name, &info->keyname);
+ AssignDomainName(&tsig.namestorage, &info->keyname);
MD5_Update(&c, info->keyname.c, DomainNameLength(&info->keyname));
// class
utc48[1] = 0;
utc48[2] = (mDNSu8)((utc32 >> 24) & 0xff);
utc48[3] = (mDNSu8)((utc32 >> 16) & 0xff);
- utc48[4] = (mDNSu8)((utc32 >> 8) & 0xff);
+ utc48[4] = (mDNSu8)((utc32 >> 8) & 0xff);
utc48[5] = (mDNSu8)( utc32 & 0xff);
- mDNSPlatformMemCopy(utc48, rdata, 6);
+ mDNSPlatformMemCopy(rdata, utc48, 6);
rdata += 6;
MD5_Update(&c, utc48, 6);
- // fudge
- buf = mDNSOpaque16fromIntVal(300); // 300 sec is fudge recommended in RFC 2485
- rdata[0] = buf.b[0];
- rdata[1] = buf.b[1];
+ // 300 sec is fudge recommended in RFC 2485
+ rdata[0] = (mDNSu8)((300 >> 8) & 0xff);
+ rdata[1] = (mDNSu8)( 300 & 0xff);
+ MD5_Update(&c, rdata, sizeof(mDNSOpaque16));
rdata += sizeof(mDNSOpaque16);
- MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
- // digest error and other data len (both zero) - we'll add them to the rdata later
- buf.NotAnInteger = 0;
+ // digest error (tcode) and other data len (zero) - we'll add them to the rdata later
+ buf.b[0] = (mDNSu8)((tcode >> 8) & 0xff);
+ buf.b[1] = (mDNSu8)( tcode & 0xff);
MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // error
+ buf.NotAnInteger = 0;
MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // other data len
// finish the message & tsig var hash
// perform outer MD5 (outer key pad, inner digest)
MD5_Init(&c);
- MD5_Update(&c, info->key.opad, HMAC_LEN);
+ MD5_Update(&c, info->keydata_opad, HMAC_LEN);
MD5_Update(&c, digest, MD5_LEN);
MD5_Final(digest, &c);
rdata[0] = (mDNSu8)((MD5_LEN >> 8) & 0xff);
rdata[1] = (mDNSu8)( MD5_LEN & 0xff);
rdata += sizeof(mDNSOpaque16);
- mDNSPlatformMemCopy(digest, rdata, MD5_LEN); // MAC
+ mDNSPlatformMemCopy(rdata, digest, MD5_LEN); // MAC
rdata += MD5_LEN;
rdata[0] = msg->h.id.b[0]; // original ID
rdata[1] = msg->h.id.b[1];
- rdata[2] = 0; // no error
- rdata[3] = 0;
+ rdata[2] = (mDNSu8)((tcode >> 8) & 0xff);
+ rdata[3] = (mDNSu8)( tcode & 0xff);
rdata[4] = 0; // other data len
rdata[5] = 0;
rdata += 6;
tsig.resrec.rdlength = (mDNSu16)(rdata - tsig.resrec.rdata->u.data);
- *end = PutResourceRecordTTLJumbo(msg, ptr, numAdditionals, &tsig.resrec, 0);
+ *end = PutResourceRecordTTLJumbo(msg, ptr, &numAdditionals, &tsig.resrec, 0);
if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; }
- // update num additionals
- countPtr = (mDNSu8 *)&msg->h.numAdditionals; // increment (network-byte ordered) header value
- *countPtr++ = (mDNSu8)(*numAdditionals >> 8);
- *countPtr++ = (mDNSu8)(*numAdditionals & 0xFF);
+ // Write back updated numAdditionals value
+ countPtr[0] = (mDNSu8)(numAdditionals >> 8);
+ countPtr[1] = (mDNSu8)(numAdditionals & 0xFF);
return *end;
}
+mDNSexport mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord * lcr, DomainAuthInfo *info, mDNSu16 * rcode, mDNSu16 * tcode)
+ {
+ mDNSu8 * ptr = (mDNSu8*) &lcr->r.resrec.rdata->u.data;
+ mDNSs32 now;
+ mDNSs32 then;
+ mDNSu8 thisDigest[MD5_LEN];
+ mDNSu8 thatDigest[MD5_LEN];
+ mDNSu32 macsize;
+ mDNSOpaque16 buf;
+ mDNSu8 utc48[6];
+ mDNSs32 delta;
+ mDNSu16 fudge;
+ domainname * algo;
+ MD5_CTX c;
+ mDNSBool ok = mDNSfalse;
+
+ // We only support HMAC-MD5 for now
+
+ algo = (domainname*) ptr;
+
+ if (!SameDomainName(algo, &HMAC_MD5_AlgName))
+ {
+ LogMsg("ERROR: DNSDigest_VerifyMessage - TSIG algorithm not supported: %##s", algo->c);
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadKey;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ ptr += DomainNameLength(algo);
+
+ // Check the times
+
+ now = mDNSPlatformUTC();
+ if (now == -1)
+ {
+ LogMsg("ERROR: DNSDigest_VerifyMessage - mDNSPlatformUTC returned bad time -1");
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadTime;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ // Get the 48 bit time field, skipping over the first word
+
+ utc48[0] = *ptr++;
+ utc48[1] = *ptr++;
+ utc48[2] = *ptr++;
+ utc48[3] = *ptr++;
+ utc48[4] = *ptr++;
+ utc48[5] = *ptr++;
+
+ then = (mDNSs32)NToH32(utc48 + sizeof(mDNSu16));
+
+ fudge = NToH16(ptr);
+
+ ptr += sizeof(mDNSu16);
+
+ delta = (now > then) ? now - then : then - now;
+
+ if (delta > fudge)
+ {
+ LogMsg("ERROR: DNSDigest_VerifyMessage - time skew > %d", fudge);
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadTime;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ // MAC size
+
+ macsize = (mDNSu32) NToH16(ptr);
+
+ ptr += sizeof(mDNSu16);
+
+ // MAC
+
+ mDNSPlatformMemCopy(thatDigest, ptr, MD5_LEN);
+
+ // Init MD5 context, digest inner key pad and message
+
+ MD5_Init(&c);
+ MD5_Update(&c, info->keydata_ipad, HMAC_LEN);
+ MD5_Update(&c, (mDNSu8*) msg, (unsigned long)(end - (mDNSu8*) msg));
+
+ // Key name
+
+ MD5_Update(&c, lcr->r.resrec.name->c, DomainNameLength(lcr->r.resrec.name));
+
+ // Class name
+
+ buf = mDNSOpaque16fromIntVal(lcr->r.resrec.rrclass);
+ MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
+
+ // TTL
+
+ MD5_Update(&c, (mDNSu8*) &lcr->r.resrec.rroriginalttl, sizeof(lcr->r.resrec.rroriginalttl));
+
+ // Algorithm
+
+ MD5_Update(&c, algo->c, DomainNameLength(algo));
+
+ // Time
+
+ MD5_Update(&c, utc48, 6);
+
+ // Fudge
+
+ buf = mDNSOpaque16fromIntVal(fudge);
+ MD5_Update(&c, buf.b, sizeof(mDNSOpaque16));
+
+ // Digest error and other data len (both zero) - we'll add them to the rdata later
+
+ buf.NotAnInteger = 0;
+ MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // error
+ MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // other data len
+
+ // Finish the message & tsig var hash
+
+ MD5_Final(thisDigest, &c);
+
+ // perform outer MD5 (outer key pad, inner digest)
+
+ MD5_Init(&c);
+ MD5_Update(&c, info->keydata_opad, HMAC_LEN);
+ MD5_Update(&c, thisDigest, MD5_LEN);
+ MD5_Final(thisDigest, &c);
+
+ if (!mDNSPlatformMemSame(thisDigest, thatDigest, MD5_LEN))
+ {
+ LogMsg("ERROR: DNSDigest_VerifyMessage - bad signature");
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadSig;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ // set remaining rdata fields
+ ok = mDNStrue;
+
+exit:
+
+ return ok;
+ }
+
+
#ifdef __cplusplus
}
#endif
*
* Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*
* This code is completely 100% portable C. It does not depend on any external header files
* from outside the mDNS project -- all the types it expects to find are defined right here.
*
* The previous point is very important: This file does not depend on any external
- * header files. It should complile on *any* platform that has a C compiler, without
+ * header files. It should compile on *any* platform that has a C compiler, without
* making *any* assumptions about availability of so-called "standard" C functions,
* routines, or types (which may or may not be present on any given platform).
Change History (most recent first):
$Log: mDNS.c,v $
-Revision 1.535.2.3 2006/11/10 19:36:42 cheshire
-Further refinement: Only harmonize TTL if the value we're adjusting it to is at least 2 seconds
-
-Revision 1.535.2.2 2006/10/31 02:11:26 cheshire
-Compile error: Need to put back AllDNSLinkGroupv4 definition
-
-Revision 1.535.2.1 2006/10/31 01:28:06 cheshire
-<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
-
-Revision 1.535 2006/03/02 20:41:17 cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Minor code tidying and comments to reduce the risk of similar programming errors in future
-
-Revision 1.534 2006/03/02 03:25:46 cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
-
-Revision 1.533 2006/02/26 00:54:41 cheshire
-Fixes to avoid code generation warning/error on FreeBSD 7
-
-Revision 1.532 2005/12/02 20:24:36 cheshire
-<rdar://problem/4363209> Adjust cutoff time for KA list by one second
-
-Revision 1.531 2005/12/02 19:05:42 cheshire
-Tidy up constants
-
-Revision 1.530 2005/11/07 01:49:48 cheshire
-For consistency, use NonZeroTime() function instead of ?: expression
-
-Revision 1.529 2005/10/25 23:42:24 cheshire
-<rdar://problem/4316057> Error in ResolveSimultaneousProbe() when type or class don't match
-Changed switch statement to an "if"
-
-Revision 1.528 2005/10/25 23:34:22 cheshire
-<rdar://problem/4316048> RequireGoodbye state not set/respected sometimes when machine going to sleep
-
-Revision 1.527 2005/10/25 22:43:59 cheshire
-Add clarifying comments
-
-Revision 1.526 2005/10/20 00:10:33 cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-
-Revision 1.525 2005/09/24 00:47:17 cheshire
-Fix comment typos
-
-Revision 1.524 2005/09/16 21:06:49 cheshire
-Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
-
-Revision 1.523 2005/03/21 00:33:51 shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
-
-Revision 1.522 2005/03/04 21:48:12 cheshire
-<rdar://problem/4037283> Fractional time rounded down instead of up on platforms with coarse clock granularity
-
-Revision 1.521 2005/02/25 04:21:00 cheshire
-<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
-
-Revision 1.520 2005/02/16 01:14:11 cheshire
-Convert RR Cache LogOperation() calls to debugf()
-
-Revision 1.519 2005/02/15 01:57:20 cheshire
-When setting "q->LastQTxTime = m->timenow", must also clear q->RecentAnswerPkts to zero
-
-Revision 1.518 2005/02/10 22:35:17 cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.517 2005/02/03 00:21:21 cheshire
-Update comments about BIND named and zero-length TXT records
-
-Revision 1.516 2005/01/28 06:06:32 cheshire
-Update comment
-
-Revision 1.515 2005/01/27 00:21:49 cheshire
-<rdar://problem/3973798> Remove mDNSResponder sleep/wake syslog message
-
-Revision 1.514 2005/01/21 01:33:45 cheshire
-<rdar://problem/3962979> Shutdown time regression: mDNSResponder not responding to SIGTERM
-
-Revision 1.513 2005/01/21 00:07:54 cheshire
-<rdar://problem/3962717> Infinite loop when the same service is registered twice, and then suffers a name conflict
-
-Revision 1.512 2005/01/20 00:37:45 cheshire
-<rdar://problem/3941448> mDNSResponder crashed in mDNSCoreReceiveResponse
-Take care not to recycle records while they are on the CacheFlushRecords list
-
-Revision 1.511 2005/01/19 22:48:53 cheshire
-<rdar://problem/3955355> Handle services with subtypes correctly when doing mDNS_RenameAndReregisterService()
-
-Revision 1.510 2005/01/19 03:12:45 cheshire
-Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
-
-Revision 1.509 2005/01/19 03:08:49 cheshire
-<rdar://problem/3961051> CPU Spin in mDNSResponder
-Log messages to help catch and report CPU spins
-
-Revision 1.508 2005/01/18 18:56:32 cheshire
-<rdar://problem/3934245> QU responses not promoted to multicast responses when appropriate
-
-Revision 1.507 2005/01/18 01:12:07 cheshire
-<rdar://problem/3956258> Logging into VPN causes mDNSResponder to reissue multicast probes
-
-Revision 1.506 2005/01/17 23:28:53 cheshire
-Fix compile error
-
-Revision 1.505 2005/01/11 02:02:56 shersche
-Move variable declaration to the beginning of statement block
-
-Revision 1.504 2004/12/20 20:24:35 cheshire
-<rdar://problem/3928456> Network efficiency: Don't keep polling if we have at least one unique-type answer
-
-Revision 1.503 2004/12/20 18:41:47 cheshire
-<rdar://problem/3591622> Low memory support: Provide answers even when we don't have cache space
-
-Revision 1.502 2004/12/20 18:04:08 cheshire
-<rdar://problem/3923098> For now, don't put standard wide-area unicast responses in our main cache
-
-Revision 1.501 2004/12/19 23:50:18 cheshire
-<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
-Don't show "No active interface to send" messages for kDNSServiceInterfaceIndexLocalOnly services
-
-Revision 1.500 2004/12/18 03:13:46 cheshire
-<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
-
-Revision 1.499 2004/12/17 23:37:45 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.498 2004/12/17 05:25:46 cheshire
-<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
-
-Revision 1.497 2004/12/17 03:20:58 cheshire
-<rdar://problem/3925168> Don't send unicast replies we know will be ignored
-
-Revision 1.496 2004/12/16 22:18:26 cheshire
-Make AddressIsLocalSubnet() a little more selective -- ignore point-to-point interfaces
-
-Revision 1.495 2004/12/16 21:27:37 ksekar
-Fixed build failures when compiled with verbose debugging messages
-
-Revision 1.494 2004/12/16 20:46:56 cheshire
-Fix compiler warnings
-
-Revision 1.493 2004/12/16 20:13:00 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.492 2004/12/16 08:03:24 shersche
-Fix compilation error when UNICAST_DISABLED is set
-
-Revision 1.491 2004/12/11 01:52:11 cheshire
-<rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
-
-Revision 1.490 2004/12/10 20:06:25 cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced SendDelayedUnicastResponse() stack frame from 9K to 112 bytes
-
-Revision 1.489 2004/12/10 20:03:43 cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced mDNSCoreReceiveQuery() stack frame from 9K to 144 bytes
-
-Revision 1.488 2004/12/10 19:50:41 cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced SendResponses() stack frame from 9K to 176 bytes
-
-Revision 1.487 2004/12/10 19:39:13 cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced SendQueries() stack frame from 18K to 112 bytes
-
-Revision 1.486 2004/12/10 14:16:17 cheshire
-<rdar://problem/3889788> Relax update rate limiting
-We now allow an average rate of ten updates per minute.
-Updates in excess of that are rate limited, but more gently than before.
-
-Revision 1.485 2004/12/10 02:09:24 cheshire
-<rdar://problem/3898376> Modify default TTLs
-
-Revision 1.484 2004/12/09 03:15:40 ksekar
-<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
-
-Revision 1.483 2004/12/07 23:00:14 ksekar
-<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration:
-Call RecordProbeFailure even if there is no record callback
-
-Revision 1.482 2004/12/07 22:49:06 cheshire
-<rdar://problem/3908850> BIND doesn't allow zero-length TXT records
-
-Revision 1.481 2004/12/07 21:26:04 ksekar
-<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
-
-Revision 1.480 2004/12/07 20:42:33 cheshire
-Add explicit context parameter to mDNS_RemoveRecordFromService()
-
-Revision 1.479 2004/12/07 17:50:49 ksekar
-<rdar://problem/3908850> BIND doesn't allow zero-length TXT records
-
-Revision 1.478 2004/12/06 21:15:22 ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.477 2004/12/04 02:12:45 cheshire
-<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
-
-Revision 1.476 2004/11/29 23:34:31 cheshire
-On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
-is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
-only nudges the time value to 1 if the interval calculation happens to result in the value zero.
-
-Revision 1.475 2004/11/29 23:13:31 cheshire
-<rdar://problem/3484552> All unique records in a set should have the cache flush bit set
-Additional check: Make sure we don't unnecessarily send packets containing only additionals.
-(This could occur with multi-packet KA lists, if the answer and additionals were marked
-by the query packet, and then the answer were later suppressed in a subsequent KA packet.)
-
-Revision 1.474 2004/11/29 17:18:12 cheshire
-Remove "Unknown DNS packet type" message for update responses
-
-Revision 1.473 2004/11/25 01:57:52 cheshire
-<rdar://problem/3484552> All unique records in a set should have the cache flush bit set
-
-Revision 1.472 2004/11/25 01:28:09 cheshire
-<rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
-
-Revision 1.471 2004/11/25 01:10:13 cheshire
-Move code to add additional records to a subroutine called AddAdditionalsToResponseList()
-
-Revision 1.470 2004/11/24 21:54:44 cheshire
-<rdar://problem/3894475> mDNSCore not receiving unicast responses properly
-
-Revision 1.469 2004/11/24 04:50:39 cheshire
-Minor tidying
-
-Revision 1.468 2004/11/24 01:47:07 cheshire
-<rdar://problem/3780207> DNSServiceRegisterRecord should call CallBack on success.
-
-Revision 1.467 2004/11/24 01:41:28 cheshire
-Rename CompleteProbing() to AcknowledgeRecord()
-
-Revision 1.466 2004/11/23 21:08:07 ksekar
-Don't use ID to demux multicast/unicast now that unicast uses random IDs
-
-Revision 1.465 2004/11/15 20:09:21 ksekar
-<rdar://problem/3719050> Wide Area support for Add/Remove record
-
-Revision 1.464 2004/11/03 01:44:36 cheshire
-Update debugging messages
-
-Revision 1.463 2004/10/29 02:38:48 cheshire
-Fix Windows compile errors
-
-Revision 1.462 2004/10/28 19:21:07 cheshire
-Guard against registering interface with zero InterfaceID
-
-Revision 1.461 2004/10/28 19:02:16 cheshire
-Remove \n from LogMsg() call
-
-Revision 1.460 2004/10/28 03:24:40 cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
-
-Revision 1.459 2004/10/26 22:34:37 cheshire
-<rdar://problem/3468995> Need to protect mDNSResponder from unbounded packet flooding
-
-Revision 1.458 2004/10/26 20:45:28 cheshire
-Show mask in "invalid mask" message
-
-Revision 1.457 2004/10/26 06:28:36 cheshire
-Now that we don't check IP TTL any more, remove associated log message
-
-Revision 1.456 2004/10/26 06:21:42 cheshire
-Adjust mask validity check to allow an all-ones mask (for IPv6 ::1 loopback address)
-
-Revision 1.455 2004/10/26 06:11:40 cheshire
-Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
-
-Revision 1.454 2004/10/23 01:16:00 cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
-
-Revision 1.453 2004/10/22 20:52:06 ksekar
-<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
-
-Revision 1.452 2004/10/20 01:50:40 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Implemented ForceMCast mode for AuthRecords as well as for Questions
-
-Revision 1.451 2004/10/19 21:33:15 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.450 2004/10/19 17:42:59 ksekar
-Fixed compiler warnings for non-debug builds.
-
-Revision 1.449 2004/10/18 22:57:07 cheshire
-<rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
-
-Revision 1.448 2004/10/16 00:16:59 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.447 2004/10/15 00:51:21 cheshire
-<rdar://problem/3711302> Seen in console: Ignored apparent spoof mDNS Response with TTL 1
-
-Revision 1.446 2004/10/14 00:43:34 cheshire
-<rdar://problem/3815984> Services continue to announce SRV and HINFO
-
-Revision 1.445 2004/10/12 21:07:09 cheshire
-Set up m->p in mDNS_Init() before calling mDNSPlatformTimeInit()
-
-Revision 1.444 2004/10/11 17:54:16 ksekar
-Changed hashtable pointer output from debugf to verbosedebugf.
-
-Revision 1.443 2004/10/10 07:05:45 cheshire
-For consistency, use symbol "localdomain" instead of literal string
-
-Revision 1.442 2004/10/08 20:25:10 cheshire
-Change of plan for <rdar://problem/3831716> -- we're not going to do that at this time
-
-Revision 1.441 2004/10/08 03:25:01 ksekar
-<rdar://problem/3831716> domain enumeration should use LLQs
-
-Revision 1.440 2004/10/06 01:44:19 cheshire
-<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
-
-Revision 1.439 2004/10/03 23:14:11 cheshire
-Add "mDNSEthAddr" type and "zeroEthAddr" constant
-
-Revision 1.438 2004/09/29 23:07:04 cheshire
-Patch from Pavel Repin to fix compile error on Windows
-
-Revision 1.437 2004/09/28 02:23:50 cheshire
-<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
-Don't need to search the entire cache for nearly-expired records -- just the appropriate hash slot
-For records with the cache flush bit set, defer the decision until the end of the packet
-
-Revision 1.436 2004/09/28 01:27:04 cheshire
-Update incorrect log message
-
-Revision 1.435 2004/09/25 02:41:39 cheshire
-<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
-
-Revision 1.434 2004/09/25 02:32:06 cheshire
-Update comments
-
-Revision 1.433 2004/09/25 02:24:27 cheshire
-Removed unused rr->UseCount
-
-Revision 1.432 2004/09/24 21:35:17 cheshire
-<rdar://problem/3561220> Browses are no longer piggybacking on other browses
-TargetPort and TargetQID are allowed to be undefined if no question->Target is set
-
-Revision 1.431 2004/09/24 21:33:12 cheshire
-Adjust comment
-
-Revision 1.430 2004/09/24 02:15:49 cheshire
-<rdar://problem/3680865> Late conflicts don't send goodbye packets on other interfaces
-
-Revision 1.429 2004/09/24 00:20:21 cheshire
-<rdar://problem/3483349> Any rrtype is a conflict for unique records
-
-Revision 1.428 2004/09/24 00:12:25 cheshire
-Get rid of unused RRUniqueOrKnownUnique(RR)
-
-Revision 1.427 2004/09/23 20:44:11 cheshire
-<rdar://problem/3813148> Reduce timeout before expiring records on failure
-
-Revision 1.426 2004/09/23 20:21:07 cheshire
-<rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
-Associate a unique sequence number with each received packet, and only increment the count of recent answer
-packets if the packet sequence number for this answer record is not one we've already seen and counted.
-
-Revision 1.425 2004/09/23 20:14:38 cheshire
-Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
-
-Revision 1.424 2004/09/23 00:58:36 cheshire
-<rdar://problem/3781269> Rate limiting interferes with updating TXT records
-
-Revision 1.423 2004/09/23 00:50:53 cheshire
-<rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
-
-Revision 1.422 2004/09/22 02:34:46 cheshire
-Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
-
-Revision 1.421 2004/09/21 23:29:49 cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
-
-Revision 1.420 2004/09/21 23:01:42 cheshire
-Update debugf messages
-
-Revision 1.419 2004/09/21 19:51:14 cheshire
-Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
-
-Revision 1.418 2004/09/21 18:40:17 cheshire
-<rdar://problem/3376752> Adjust default record TTLs
-
-Revision 1.417 2004/09/21 17:32:16 cheshire
-<rdar://problem/3809484> Rate limiting imposed too soon
-
-Revision 1.416 2004/09/20 23:52:01 cheshire
-CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
-
-Revision 1.415 2004/09/18 01:14:09 cheshire
-<rdar://problem/3485375> Resolve() should not bother doing AAAA queries on machines with no IPv6 interfaces
-
-Revision 1.414 2004/09/18 01:06:48 cheshire
-Add comments
-
-Revision 1.413 2004/09/17 01:08:48 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.412 2004/09/17 00:46:33 cheshire
-mDNS_TimeNow should take const mDNS parameter
-
-Revision 1.411 2004/09/17 00:31:51 cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.410 2004/09/17 00:19:10 cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
-
-Revision 1.409 2004/09/16 21:59:15 cheshire
-For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
-
-Revision 1.408 2004/09/16 21:36:36 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-Changes to add necessary locking calls around unicast DNS operations
-
-Revision 1.407 2004/09/16 02:29:39 cheshire
-Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
-uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
-
-Revision 1.406 2004/09/16 01:58:14 cheshire
-Fix compiler warnings
-
-Revision 1.405 2004/09/16 00:24:48 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.404 2004/09/15 21:44:11 cheshire
-<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
-Show time value in log to help diagnose errors
-
-Revision 1.403 2004/09/15 00:46:32 ksekar
-Changed debugf to verbosedebugf in CheckCacheExpiration
-
-Revision 1.402 2004/09/14 23:59:55 cheshire
-<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
-
-Revision 1.401 2004/09/14 23:27:46 cheshire
-Fix compile errors
-
-Revision 1.400 2004/09/02 03:48:47 cheshire
-<rdar://problem/3709039> Disable targeted unicast query support by default
-1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
-2. New field AllowRemoteQuery in AuthRecord structure
-3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
-4. mDNS.c only answers remote queries if AllowRemoteQuery is set
-
-Revision 1.399 2004/09/02 01:39:40 cheshire
-For better readability, follow consistent convention that QR bit comes first, followed by OP bits
-
-Revision 1.398 2004/09/01 03:59:29 ksekar
-<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
-
-Revision 1.397 2004/08/25 22:04:25 rpantos
-Fix the standard Windows compile error.
-
-Revision 1.396 2004/08/25 00:37:27 ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
-
-Revision 1.395 2004/08/18 17:21:18 ksekar
-Removed double-call of uDNS_AdvertiseInterface from mDNS_SetFQDNs()
-
-Revision 1.394 2004/08/14 03:22:41 cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
-
-Revision 1.393 2004/08/13 23:42:52 cheshire
-Removed unused "zeroDomainNamePtr"
-
-Revision 1.392 2004/08/13 23:37:02 cheshire
-Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
-"uDNS_info.UnicastHostname" for clarity
-
-Revision 1.391 2004/08/13 23:25:00 cheshire
-Now that we do both uDNS and mDNS, global replace "m->hostname" with
-"m->MulticastHostname" for clarity
-
-Revision 1.390 2004/08/11 02:17:01 cheshire
-<rdar://problem/3514236> Registering service with port number 0 should create a "No Such Service" record
-
-Revision 1.389 2004/08/10 23:19:14 ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
-
-Revision 1.388 2004/07/30 17:40:06 ksekar
-<rdar://problem/3739115>: TXT Record updates not available for wide-area services
-
-Revision 1.387 2004/07/26 22:49:30 ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
-
-Revision 1.386 2004/07/13 21:24:24 rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.385 2004/06/18 19:09:59 cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
-
-Revision 1.384 2004/06/15 04:31:23 cheshire
-Make sure to clear m->CurrentRecord at the end of AnswerNewLocalOnlyQuestion()
-
-Revision 1.383 2004/06/11 00:04:59 cheshire
-<rdar://problem/3595602> TTL must be greater than zero for DNSServiceRegisterRecord
-
-Revision 1.382 2004/06/08 04:59:40 cheshire
-Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
-
-Revision 1.381 2004/06/05 00:57:30 cheshire
-Remove incorrect LogMsg()
-
-Revision 1.380 2004/06/05 00:04:26 cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
-
-Revision 1.379 2004/05/28 23:42:36 ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
-
-Revision 1.378 2004/05/25 17:25:25 cheshire
-Remove extraneous blank lines and white space
-
-Revision 1.377 2004/05/18 23:51:25 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.376 2004/05/05 18:30:44 ksekar
-Restored surpressed Cache Tail debug messages.
-
-Revision 1.375 2004/04/26 21:36:25 cheshire
-Only send IPv4 (or v6) multicast when IPv4 (or v6) multicast send/receive
-is indicated as being available on that interface
-
-Revision 1.374 2004/04/21 02:53:26 cheshire
-Typo in debugf statement
-
-Revision 1.373 2004/04/21 02:49:11 cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
-
-Revision 1.372 2004/04/21 02:38:51 cheshire
-Add debugging checks
-
-Revision 1.371 2004/04/14 23:09:28 ksekar
-Support for TSIG signed dynamic updates.
-
-Revision 1.370 2004/04/09 17:40:26 cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
-
-Revision 1.369 2004/04/09 16:34:00 cheshire
-Debugging code for later; currently unused
-
-Revision 1.368 2004/04/02 19:19:48 cheshire
-Add code to do optional logging of multi-packet KA list time intervals
-
-Revision 1.367 2004/03/20 03:16:10 cheshire
-Minor refinement to "Excessive update rate" message
-
-Revision 1.366 2004/03/20 03:12:57 cheshire
-<rdar://problem/3587619>: UpdateCredits not granted promptly enough
-
-Revision 1.365 2004/03/19 23:51:22 cheshire
-Change to use symbolic constant kUpdateCreditRefreshInterval instead of (mDNSPlatformOneSecond * 60)
-
-Revision 1.364 2004/03/13 01:57:33 ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
-
-Revision 1.363 2004/03/12 21:00:51 cheshire
-Also show port numbers when logging "apparent spoof mDNS Response" messages
-
-Revision 1.362 2004/03/12 08:58:18 cheshire
-Guard against empty TXT records
-
-Revision 1.361 2004/03/09 03:00:46 cheshire
-<rdar://problem/3581961> Don't take lock until after mDNS_Update() has validated that the data is good.
-
-Revision 1.360 2004/03/08 02:52:41 cheshire
-Minor debugging fix: Make sure 'target' is initialized so we don't crash writing debugging log messages
-
-Revision 1.359 2004/03/02 03:21:56 cheshire
-<rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
-
-Revision 1.358 2004/02/20 08:18:34 cheshire
-<rdar://problem/3564799>: mDNSResponder sometimes announces AAAA records unnecessarily
-
-Revision 1.357 2004/02/18 01:47:41 cheshire
-<rdar://problem/3553472>: Insufficient delay waiting for multi-packet KA lists causes AirPort traffic storms
-
-Revision 1.356 2004/02/06 23:04:19 ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
-
-Revision 1.355 2004/02/05 09:32:33 cheshire
-Fix from Bob Bradley: When using the "%.*s" string form,
-guard against truncating in the middle of a multi-byte UTF-8 character.
-
-Revision 1.354 2004/02/05 09:30:22 cheshire
-Update comments
-
-Revision 1.353 2004/01/28 03:41:00 cheshire
-<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
-
-Revision 1.352 2004/01/28 02:30:07 ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane. Stopped sending unicast messages on
-every interface. Fixed unicast resolving via mach-port API.
-
-Revision 1.351 2004/01/27 20:15:22 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
-
-Revision 1.350 2004/01/24 23:38:16 cheshire
-Use mDNSVal16() instead of shifting and ORing operations
-
-Revision 1.349 2004/01/23 23:23:14 ksekar
-Added TCP support for truncated unicast messages.
-
-Revision 1.348 2004/01/22 03:54:11 cheshire
-Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
-which means "do this query via multicast, even if it's apparently a unicast domain"
-
-Revision 1.347 2004/01/22 03:50:49 cheshire
-If the client has specified an explicit InterfaceID, then do query by multicast, not unicast
-
-Revision 1.346 2004/01/22 03:48:41 cheshire
-Make sure uDNS client doesn't accidentally use query ID zero
-
-Revision 1.345 2004/01/22 03:43:08 cheshire
-Export constants like mDNSInterface_LocalOnly so that the client layers can use them
-
-Revision 1.344 2004/01/21 21:53:18 cheshire
-<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
-
-Revision 1.343 2003/12/23 00:07:47 cheshire
-Make port number in debug message be five-character field, left justified
-
-Revision 1.342 2003/12/20 01:34:28 cheshire
-<rdar://problem/3515876>: Error putting additional records into packets
-Another fix from Rampi: responseptr needs to be updated inside the "for" loop,
-after every record, not once at the end.
-
-Revision 1.341 2003/12/18 22:56:12 cheshire
-<rdar://problem/3510798>: Reduce syslog messages about ignored spoof packets
-
-Revision 1.340 2003/12/16 02:31:37 cheshire
-Minor update to comments
-
-Revision 1.339 2003/12/13 05:50:33 bradley
-Fixed crash with mDNS_Lock/Unlock being called for the initial GrowCache before the platform
-layer has been initialized. Protect mDNS_reentrancy when completing the core initialization to
-fix a race condition during async initialization. Fixed buffer overrun for 1 byte mDNS_snprintf.
-
-Revision 1.338 2003/12/13 03:05:27 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
-
-Revision 1.337 2003/12/01 21:46:05 cheshire
-mDNS_StartQuery returns mStatus_BadInterfaceErr if the specified interface does not exist
-
-Revision 1.336 2003/12/01 21:26:19 cheshire
-Guard against zero-length sbuffer in mDNS_vsnprintf()
-
-Revision 1.335 2003/12/01 20:27:48 cheshire
-Display IPv6 addresses correctly (e.g. in log messages) on little-endian processors
-
-Revision 1.334 2003/11/20 22:59:53 cheshire
-Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
-Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
-
-Revision 1.333 2003/11/20 20:49:53 cheshire
-Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
-
-Revision 1.332 2003/11/20 05:47:37 cheshire
-<rdar://problem/3490355>: Don't exclude known answers whose expiry time is before the next query
-Now that we only include answers in the known answer list if they are less than
-halfway to expiry, the check to also see if we have another query scheduled
-before the record expires is no longer necessary (and in fact, not correct).
-
-Revision 1.331 2003/11/19 22:31:48 cheshire
-When automatically adding A records to SRVs, add them as additionals, not answers
-
-Revision 1.330 2003/11/19 22:28:50 cheshire
-Increment/Decrement mDNS_reentrancy around calls to m->MainCallback()
-to allow client to make mDNS calls (specifically the call to mDNS_GrowCache())
-
-Revision 1.329 2003/11/19 22:19:24 cheshire
-Show log message when ignoring packets with bad TTL.
-This is to help diagnose problems on Linux versions that may not report the TTL reliably.
-
-Revision 1.328 2003/11/19 22:06:38 cheshire
-Show log messages when a service or hostname is renamed
-
-Revision 1.327 2003/11/19 22:03:44 cheshire
-Move common "m->NextScheduledResponse = m->timenow" to before "if" statement
-
-Revision 1.326 2003/11/17 22:27:02 cheshire
-Another fix from ramaprasad.kr@hp.com: Improve reply delay computation
-on platforms that have native clock rates below fifty ticks per second.
-
-Revision 1.325 2003/11/17 20:41:44 cheshire
-Fix some missing mDNS_Lock(m)/mDNS_Unlock(m) calls.
-
-Revision 1.324 2003/11/17 20:36:32 cheshire
-Function rename: Remove "mDNS_" prefix from AdvertiseInterface() and
-DeadvertiseInterface() -- they're internal private routines, not API routines.
-
-Revision 1.323 2003/11/14 20:59:08 cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.322 2003/11/14 19:47:52 cheshire
-Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
-
-Revision 1.321 2003/11/14 19:18:34 cheshire
-Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
-
-Revision 1.320 2003/11/13 06:45:04 cheshire
-Fix compiler warning on certain compilers
-
-Revision 1.319 2003/11/13 00:47:40 cheshire
-<rdar://problem/3437556> We should delay AAAA record query if A record already in cache.
-
-Revision 1.318 2003/11/13 00:33:26 cheshire
-Change macro "RRIsAddressType" to "RRTypeIsAddressType"
-
-Revision 1.317 2003/11/13 00:10:49 cheshire
-<rdar://problem/3436412>: Verify that rr data is different before updating.
-
-Revision 1.316 2003/11/08 23:37:54 cheshire
-Give explicit zero initializers to blank static structure, required by certain compilers.
-(Thanks to ramaprasad.kr@hp.com for reporting this.)
-
-Revision 1.315 2003/11/07 03:32:56 cheshire
-<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
-This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
-purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
-to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
-can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
-
-Revision 1.314 2003/11/07 03:19:49 cheshire
-Minor variable renaming for clarity
-
-Revision 1.313 2003/11/07 03:14:49 cheshire
-Previous checkin proved to be overly simplistic; reversing
-
-Revision 1.312 2003/11/03 23:45:15 cheshire
-<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
-Build cache lists in FIFO order, not customary C LIFO order
-(Append new elements to tail of cache list, instead of prepending at the head.)
-
-Revision 1.311 2003/10/09 18:00:11 cheshire
-Another compiler warning fix.
-
-Revision 1.310 2003/10/07 20:27:05 cheshire
-Patch from Bob Bradley, to fix warning and compile error on Windows
-
-Revision 1.309 2003/09/26 01:06:36 cheshire
-<rdar://problem/3427923> Set kDNSClass_UniqueRRSet bit for updates too
-Made new routine HaveSentEntireRRSet() to check if flag should be set
-
-Revision 1.308 2003/09/23 01:05:01 cheshire
-Minor changes to comments and debugf() message
-
-Revision 1.307 2003/09/09 20:13:30 cheshire
-<rdar://problem/3411105> Don't send a Goodbye record if we never announced it
-Ammend checkin 1.304: Off-by-one error: By this place in the function we've already decremented
-rr->AnnounceCount, so the check needs to be for InitialAnnounceCount-1, not InitialAnnounceCount
-
-Revision 1.306 2003/09/09 03:00:03 cheshire
-<rdar://problem/3413099> Services take a long time to disappear when switching networks.
-Added two constants: kDefaultReconfirmTimeForNoAnswer and kDefaultReconfirmTimeForCableDisconnect
-
-Revision 1.305 2003/09/09 02:49:31 cheshire
-<rdar://problem/3413975> Initial probes and queries not grouped on wake-from-sleep
+Revision 1.729 2007/10/05 17:56:10 cheshire
+Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
-Revision 1.304 2003/09/09 02:41:19 cheshire
-<rdar://problem/3411105> Don't send a Goodbye record if we never announced it
+Revision 1.728 2007/10/04 23:18:14 cheshire
+<rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
-Revision 1.303 2003/09/05 19:55:02 cheshire
-<rdar://problem/3409533> Include address records when announcing SRV records
+Revision 1.727 2007/10/04 22:51:57 cheshire
+Added debugging LogOperation message to show when we're sending cache expiration queries
-Revision 1.302 2003/09/05 00:01:36 cheshire
-<rdar://problem/3407549> Don't accelerate queries that have large KA lists
+Revision 1.726 2007/10/03 00:14:24 cheshire
+Removed write to null to generate stack trace for SetNextQueryTime locking failure
-Revision 1.301 2003/09/04 22:51:13 cheshire
-<rdar://problem/3398213> Group probes and goodbyes better
+Revision 1.725 2007/10/02 21:11:08 cheshire
+<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
-Revision 1.300 2003/09/03 02:40:37 cheshire
-<rdar://problem/3404842> mDNSResponder complains about '_'s
-Underscores are not supposed to be legal in standard DNS names, but IANA appears
-to have allowed them in previous service name registrations, so we should too.
+Revision 1.724 2007/10/02 20:10:23 cheshire
+Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
-Revision 1.299 2003/09/03 02:33:09 cheshire
-<rdar://problem/3404795> CacheRecordRmv ERROR
-Don't update m->NewQuestions until *after* CheckCacheExpiration();
+Revision 1.723 2007/10/02 19:56:54 cheshire
+<rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
-Revision 1.298 2003/09/03 01:47:01 cheshire
-<rdar://problem/3319418> Services always in a state of flux
-Change mDNS_Reconfirm_internal() minimum timeout from 5 seconds to 45-60 seconds
+Revision 1.722 2007/10/01 22:59:46 cheshire
+<rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
+Need to shut down NATTraversals on exit
-Revision 1.297 2003/08/29 19:44:15 cheshire
-<rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
-1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
- that already have at least one unique answer in the cache
-2. For these queries, go straight to QM, skipping QU
+Revision 1.721 2007/10/01 18:42:07 cheshire
+To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
-Revision 1.296 2003/08/29 19:08:21 cheshire
-<rdar://problem/3400986> Traffic reduction: Eliminate huge KA lists after wake from sleep
-Known answers are no longer eligible to go in the KA list if they are more than half-way to their expiry time.
+Revision 1.720 2007/09/29 20:40:19 cheshire
+<rdar://problem/5513378> Crash in ReissueBlockedQuestions
-Revision 1.295 2003/08/28 01:10:59 cheshire
-<rdar://problem/3396034> Add syslog message to report when query is reset because of immediate answer burst
+Revision 1.719 2007/09/27 22:23:56 cheshire
+<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
+Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
-Revision 1.294 2003/08/27 02:30:22 cheshire
-<rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
-One more change: "query->GotTXT" is now a straightforward bi-state boolean again
+Revision 1.718 2007/09/27 22:02:33 cheshire
+<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
-Revision 1.293 2003/08/27 02:25:31 cheshire
-<rdar://problem/3395909> Traffic Reduction: Inefficiencies in DNSServiceResolverResolve()
+Revision 1.717 2007/09/27 21:21:39 cheshire
+Export CompleteDeregistration so it's callable from other files
-Revision 1.292 2003/08/21 19:27:36 cheshire
-<rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
+Revision 1.716 2007/09/27 02:12:21 cheshire
+Updated GrantCacheExtensions degugging message to show new record lifetime
-Revision 1.291 2003/08/21 18:57:44 cheshire
-<rdar://problem/3387140> Synchronized queries on the network
+Revision 1.715 2007/09/27 01:20:06 cheshire
+<rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
-Revision 1.290 2003/08/21 02:25:23 cheshire
-Minor changes to comments and debugf() messages
+Revision 1.714 2007/09/27 00:37:01 cheshire
+<rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
-Revision 1.289 2003/08/21 02:21:50 cheshire
-<rdar://problem/3386473> Efficiency: Reduce repeated queries
+Revision 1.713 2007/09/27 00:25:39 cheshire
+Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
+<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-Revision 1.288 2003/08/20 23:39:30 cheshire
-<rdar://problem/3344098> Review syslog messages, and remove as appropriate
+Revision 1.712 2007/09/26 23:16:58 cheshire
+<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
-Revision 1.287 2003/08/20 20:47:18 cheshire
-Fix compiler warning
+Revision 1.711 2007/09/26 22:06:02 cheshire
+<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
-Revision 1.286 2003/08/20 02:18:51 cheshire
-<rdar://problem/3344098> Cleanup: Review syslog messages
+Revision 1.710 2007/09/26 00:49:46 cheshire
+Improve packet logging to show sent and received packets,
+transport protocol (UDP/TCP/TLS) and source/destination address:port
-Revision 1.285 2003/08/20 01:59:06 cheshire
-<rdar://problem/3384478> rdatahash and rdnamehash not updated after changing rdata
-Made new routine SetNewRData() to update rdlength, rdestimate, rdatahash and rdnamehash in one place
+Revision 1.709 2007/09/21 21:12:36 cheshire
+<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
-Revision 1.284 2003/08/19 22:20:00 cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
+Revision 1.708 2007/09/20 23:13:37 cheshire
+<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
+Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
-Revision 1.283 2003/08/19 22:16:27 cheshire
-Minor fix: Add missing "mDNS_Unlock(m);" in mDNS_DeregisterInterface() error case.
+Revision 1.707 2007/09/20 02:29:37 cheshire
+<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
-Revision 1.282 2003/08/19 06:48:25 cheshire
-<rdar://problem/3376552> Guard against excessive record updates
-Each record starts with 10 UpdateCredits.
-Every update consumes one UpdateCredit.
-UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
-As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
-When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
+Revision 1.706 2007/09/20 01:13:19 cheshire
+Export CacheGroupForName so it's callable from other files
-Revision 1.281 2003/08/19 04:49:28 cheshire
-<rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
-1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
-2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
-3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
+Revision 1.705 2007/09/20 01:12:06 cheshire
+Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
-Revision 1.280 2003/08/19 02:33:36 cheshire
-Update comments
+Revision 1.704 2007/09/19 22:47:25 cheshire
+<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
-Revision 1.279 2003/08/19 02:31:11 cheshire
-<rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
-Final expiration queries now only mark the question for sending on the particular interface
-pertaining to the record that's expiring.
+Revision 1.703 2007/09/14 01:46:59 cheshire
+Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
-Revision 1.278 2003/08/18 22:53:37 cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
+Revision 1.702 2007/09/13 22:06:46 cheshire
+<rdar://problem/5480643> Tully's Free WiFi: DNS fails
+Need to accept DNS responses where the query ID field matches, even if the source address does not
-Revision 1.277 2003/08/18 19:05:44 cheshire
-<rdar://problem/3382423> UpdateRecord not working right
-Added "newrdlength" field to hold new length of updated rdata
+Revision 1.701 2007/09/12 23:22:32 cheshire
+<rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
-Revision 1.276 2003/08/16 03:39:00 cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
+Revision 1.700 2007/09/12 23:03:08 cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-Revision 1.275 2003/08/16 02:51:27 cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-Don't try to compute namehash etc, until *after* validating the name
+Revision 1.699 2007/09/12 22:19:28 cheshire
+<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
-Revision 1.274 2003/08/16 01:12:40 cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-Now that the minimum rdata object size has been reduced to 64 bytes, it is no longer safe to do a
-simple C structure assignment of a domainname, because that object is defined to be 256 bytes long,
-and in the process of copying it, the C compiler may run off the end of the rdata object into
-unmapped memory. All assignments of domainname objects of uncertain size are now replaced with a
-call to the macro AssignDomainName(), which is careful to copy only as many bytes as are valid.
+Revision 1.698 2007/09/12 22:13:27 cheshire
+Remove DynDNSHostNames cleanly on shutdown
-Revision 1.273 2003/08/15 20:16:02 cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
- Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
- compute a hash of the rdata and store the hash in the ResourceRecord object.
+Revision 1.697 2007/09/12 01:44:47 cheshire
+<rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
-Revision 1.272 2003/08/14 19:29:04 cheshire
-<rdar://problem/3378473> Include cache records in SIGINFO output
-Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
+Revision 1.696 2007/09/12 01:26:08 cheshire
+Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
-Revision 1.271 2003/08/14 02:17:05 cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+Revision 1.695 2007/09/11 19:19:16 cheshire
+Correct capitalization of "uPNP" to "UPnP"
-Revision 1.270 2003/08/13 17:07:28 ksekar
-<rdar://problem/3376458>: Extra RR linked to list even if registration fails - causes crash
-Added check to result of mDNS_Register() before linking extra record into list.
+Revision 1.694 2007/09/10 22:06:51 cheshire
+Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
-Revision 1.269 2003/08/12 19:56:23 cheshire
-Update to APSL 2.0
+Revision 1.693 2007/09/07 22:24:36 vazquez
+<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
-Revision 1.268 2003/08/12 15:01:10 cheshire
-Add comments
+Revision 1.692 2007/09/07 00:12:09 cheshire
+<rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
-Revision 1.267 2003/08/12 14:59:27 cheshire
-<rdar://problem/3374490> Rate-limiting blocks some legitimate responses
-When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
-whether to suppress the response, also check LastMCInterface to see if it matches.
+Revision 1.691 2007/09/05 22:25:01 vazquez
+<rdar://problem/5400521> update_record mDNSResponder leak
-Revision 1.266 2003/08/12 12:47:16 cheshire
-In mDNSCoreMachineSleep debugf message, display value of m->timenow
+Revision 1.690 2007/09/05 21:48:01 cheshire
+<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
+Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs
+to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
+otherwise those records will expire and vanish from the cache.
-Revision 1.265 2003/08/11 20:04:28 cheshire
-<rdar://problem/3366553> Improve efficiency by restricting cases where we have to walk the entire cache
+Revision 1.689 2007/09/05 02:29:06 cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+Additional fixes to code implementing "NoAnswer" logic
-Revision 1.264 2003/08/09 00:55:02 cheshire
-<rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
-Don't scan the whole cache after every packet.
+Revision 1.688 2007/08/31 22:56:39 cheshire
+<rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
-Revision 1.263 2003/08/09 00:35:29 cheshire
-Moved AnswerNewQuestion() later in the file, in preparation for next checkin
+Revision 1.687 2007/08/31 19:53:14 cheshire
+<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
+If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
-Revision 1.262 2003/08/08 19:50:33 cheshire
-<rdar://problem/3370332> Remove "Cache size now xxx" messages
+Revision 1.686 2007/08/30 00:01:56 cheshire
+Added comment about SetTargetToHostName()
-Revision 1.261 2003/08/08 19:18:45 cheshire
-<rdar://problem/3271219> Only retrigger questions on platforms with the "PhantomInterfaces" bug
+Revision 1.685 2007/08/29 01:19:24 cheshire
+<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
+Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
-Revision 1.260 2003/08/08 18:55:48 cheshire
-<rdar://problem/3370365> Guard against time going backwards
+Revision 1.684 2007/08/28 23:58:42 cheshire
+Rename HostTarget -> AutoTarget
-Revision 1.259 2003/08/08 18:36:04 cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
+Revision 1.683 2007/08/28 23:53:21 cheshire
+Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
-Revision 1.258 2003/08/08 16:22:05 cheshire
-<rdar://problem/3335473> Need to check validity of TXT (and other) records
-Remove unneeded LogMsg
+Revision 1.682 2007/08/27 20:28:19 cheshire
+Improve "suspect uDNS response" log message
-Revision 1.257 2003/08/07 01:41:08 cheshire
-<rdar://problem/3367346> Ignore packets with invalid source address (all zeroes or all ones)
+Revision 1.681 2007/08/24 23:37:23 cheshire
+Added debugging message to show when ExtraResourceRecord callback gets invoked
-Revision 1.256 2003/08/06 23:25:51 cheshire
-<rdar://problem/3290674> Increase TTL for A/AAAA/SRV from one minute to four
+Revision 1.680 2007/08/24 00:15:19 cheshire
+Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
-Revision 1.255 2003/08/06 23:22:50 cheshire
-Add symbolic constants: kDefaultTTLforUnique (one minute) and kDefaultTTLforShared (two hours)
+Revision 1.679 2007/08/23 21:47:09 vazquez
+<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
+make sure we clean up port mappings on base stations by sending a lease value of 0,
+and only send NAT-PMP packets on private networks; also save some memory by
+not using packet structs in NATTraversals.
-Revision 1.254 2003/08/06 21:33:39 cheshire
-Fix compiler warnings on PocketPC 2003 (Windows CE)
+Revision 1.678 2007/08/01 16:09:13 cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-Revision 1.253 2003/08/06 20:43:57 cheshire
-<rdar://problem/3335473> Need to check validity of TXT (and other) records
-Created ValidateDomainName() and ValidateRData(), used by mDNS_Register_internal() and mDNS_Update()
+Revision 1.677 2007/08/01 01:58:24 cheshire
+Added RecordType sanity check in mDNS_Register_internal
-Revision 1.252 2003/08/06 20:35:47 cheshire
-Enhance debugging routine GetRRDisplayString() so it can also be used to display
-other RDataBody objects, not just the one currently attached the given ResourceRecord
+Revision 1.676 2007/08/01 00:04:13 cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
-Revision 1.251 2003/08/06 19:07:34 cheshire
-<rdar://problem/3366251> mDNSResponder not inhibiting multicast responses as much as it should
-Was checking LastAPTime instead of LastMCTime
+Revision 1.675 2007/07/31 02:28:35 vazquez
+<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-Revision 1.250 2003/08/06 19:01:55 cheshire
-Update comments
+Revision 1.674 2007/07/31 01:57:23 cheshire
+Adding code to respect TTL received in uDNS responses turned out to
+expose other problems; backing out change for now.
-Revision 1.249 2003/08/06 00:13:28 cheshire
-Tidy up debugf messages
+Revision 1.673 2007/07/30 23:31:26 cheshire
+Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
-Revision 1.248 2003/08/05 22:20:15 cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
+Revision 1.672 2007/07/28 01:25:56 cheshire
+<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
-Revision 1.247 2003/08/05 00:56:39 cheshire
-<rdar://problem/3357075> mDNSResponder sending additional records, even after precursor record suppressed
+Revision 1.671 2007/07/27 22:32:54 cheshire
+When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
+of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
-Revision 1.246 2003/08/04 19:20:49 cheshire
-Add kDNSQType_ANY to list in DNSTypeName() so it can be displayed in debugging messages
+Revision 1.670 2007/07/27 20:54:43 cheshire
+Fixed code to respect real record TTL received in uDNS responses
-Revision 1.245 2003/08/02 01:56:29 cheshire
-For debugging: log message if we ever get more than one question in a truncated packet
+Revision 1.669 2007/07/27 20:09:32 cheshire
+Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
-Revision 1.244 2003/08/01 23:55:32 cheshire
-Fix for compiler warnings on Windows, submitted by Bob Bradley
+Revision 1.668 2007/07/27 19:58:47 cheshire
+Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
-Revision 1.243 2003/07/25 02:26:09 cheshire
-Typo: FIxed missing semicolon
+Revision 1.667 2007/07/27 19:52:10 cheshire
+Don't increment m->rrcache_active for no-cache add events
-Revision 1.242 2003/07/25 01:18:41 cheshire
-Fix memory leak on shutdown in mDNS_Close() (detected in Windows version)
+Revision 1.666 2007/07/27 19:30:39 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
-Revision 1.241 2003/07/23 21:03:42 cheshire
-Only show "Found record..." debugf message in verbose mode
+Revision 1.665 2007/07/27 18:44:01 cheshire
+Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
-Revision 1.240 2003/07/23 21:01:11 cheshire
-<rdar://problem/3340584> Need Nagle-style algorithm to coalesce multiple packets into one
-After sending a packet, suppress further sending for the next 100ms.
+Revision 1.664 2007/07/27 18:38:56 cheshire
+Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
-Revision 1.239 2003/07/22 01:30:05 cheshire
-<rdar://problem/3329099> Don't try to add the same question to the duplicate-questions list more than once
+Revision 1.663 2007/07/25 03:05:02 vazquez
+Fixes for:
+<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
+<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
+and a myriad of other security problems
-Revision 1.238 2003/07/22 00:10:20 cheshire
-<rdar://problem/3337355> ConvertDomainLabelToCString() needs to escape escape characters
+Revision 1.662 2007/07/24 20:22:46 cheshire
+Make sure all fields of main mDNS object are initialized correctly
-Revision 1.237 2003/07/19 03:23:13 cheshire
-<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
+Revision 1.661 2007/07/21 00:54:45 cheshire
+<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
-Revision 1.236 2003/07/19 03:04:55 cheshire
-Fix warnings; some debugf message improvements
+Revision 1.660 2007/07/20 20:00:45 cheshire
+"Legacy Browse" is better called "Automatic Browse"
-Revision 1.235 2003/07/19 00:03:32 cheshire
-<rdar://problem/3160248> ScheduleNextTask needs to be smarter after a no-op packet is received
-ScheduleNextTask is quite an expensive operation.
-We don't need to do all that work after receiving a no-op packet that didn't change our state.
+Revision 1.659 2007/07/20 00:54:18 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Revision 1.234 2003/07/18 23:52:11 cheshire
-To improve consistency of field naming, global search-and-replace:
-NextProbeTime -> NextScheduledProbe
-NextResponseTime -> NextScheduledResponse
+Revision 1.658 2007/07/18 02:28:57 cheshire
+Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
-Revision 1.233 2003/07/18 00:29:59 cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+Revision 1.657 2007/07/18 00:57:10 cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+Only need to call AddNewClientTunnel() for IPv6 addresses
-Revision 1.232 2003/07/18 00:11:38 cheshire
-Add extra case to switch statements to handle HINFO data for Get, Put and Display
-(In all but GetRDLength(), this is is just a fall-through to kDNSType_TXT)
+Revision 1.656 2007/07/16 23:54:48 cheshire
+<rdar://problem/5338850> Crash when removing or changing DNS keys
-Revision 1.231 2003/07/18 00:06:37 cheshire
-To make code a little easier to read in GetRDLength(), search-and-replace "rr->rdata->u." with "rd->"
+Revision 1.655 2007/07/16 20:11:37 vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
+Init LNT stuff and handle SSDP packets
-Revision 1.230 2003/07/17 18:16:54 cheshire
-<rdar://problem/3319418> Services always in a state of flux
-In preparation for working on this, made some debugf messages a little more selective
+Revision 1.654 2007/07/12 23:30:23 cheshire
+Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
-Revision 1.229 2003/07/17 17:35:04 cheshire
-<rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
+Revision 1.653 2007/07/12 02:51:27 cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Revision 1.228 2003/07/16 20:50:27 cheshire
-<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
+Revision 1.652 2007/07/11 23:43:42 cheshire
+Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
-Revision 1.227 2003/07/16 05:01:36 cheshire
-Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
-<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
+Revision 1.651 2007/07/11 22:44:40 cheshire
+<rdar://problem/5328801> SIGHUP should purge the cache
-Revision 1.226 2003/07/16 04:51:44 cheshire
-Fix use of constant 'mDNSPlatformOneSecond' where it should have said 'InitialQuestionInterval'
+Revision 1.650 2007/07/11 21:34:09 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
-Revision 1.225 2003/07/16 04:46:41 cheshire
-Minor wording cleanup: The correct DNS term is "response", not "reply"
+Revision 1.649 2007/07/11 02:52:52 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+In uDNS_RegisterService, set HostTarget for AutoTunnel services
-Revision 1.224 2003/07/16 04:39:02 cheshire
-Textual cleanup (no change to functionality):
-Construct "c >= 'A' && c <= 'Z'" appears in too many places; replaced with macro "mDNSIsUpperCase(c)"
+Revision 1.648 2007/07/09 23:48:12 cheshire
+Add parentheses around bitwise operation for clarity
-Revision 1.223 2003/07/16 00:09:22 cheshire
-Textual cleanup (no change to functionality):
-Construct "((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" appears in too many places;
-replace with macro "TicksTTL(rr)"
-Construct "rr->TimeRcvd + ((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)"
-replaced with macro "RRExpireTime(rr)"
+Revision 1.647 2007/07/06 21:17:55 cheshire
+Initialize m->retryGetAddr to timenow + 0x78000000;
-Revision 1.222 2003/07/15 23:40:46 cheshire
-Function rename: UpdateDupSuppressInfo() is more accurately called ExpireDupSuppressInfo()
+Revision 1.646 2007/07/06 18:55:49 cheshire
+Initialize m->NextScheduledNATOp
-Revision 1.221 2003/07/15 22:17:56 cheshire
-<rdar://problem/3328394> mDNSResponder is not being efficient when doing certain queries
+Revision 1.645 2007/06/29 22:55:54 cheshire
+Move declaration of DNSServer *s; Fixed incomplete comment.
-Revision 1.220 2003/07/15 02:12:51 cheshire
-Slight tidy-up of debugf messages and comments
+Revision 1.644 2007/06/29 00:07:29 vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-Revision 1.219 2003/07/15 01:55:12 cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
+Revision 1.643 2007/06/20 01:10:12 cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-Revision 1.218 2003/07/14 16:26:06 cheshire
-<rdar://problem/3324795> Duplicate query suppression not working right
-Refinement: Don't record DS information for a question in the first quarter second
-right after we send it -- in the case where a question happens to be accelerated by
-the maximum allowed amount, we don't want it to then be suppressed because the previous
-time *we* sent that question falls (just) within the valid duplicate suppression window.
+Revision 1.642 2007/06/15 21:54:50 cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-Revision 1.217 2003/07/13 04:43:53 cheshire
-<rdar://problem/3325169> Services on multiple interfaces not always resolving
-Minor refinement: No need to make address query broader than the original SRV query that provoked it
+Revision 1.641 2007/05/25 00:30:24 cheshire
+When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
+status matches. This is particularly important when doing a private query for an SOA record,
+which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
+If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
-Revision 1.216 2003/07/13 03:13:17 cheshire
-<rdar://problem/3325169> Services on multiple interfaces not always resolving
-If we get an identical SRV on a second interface, convert address queries to non-specific
+Revision 1.640 2007/05/25 00:25:44 cheshire
+<rdar://problem/5227737> Need to enhance putRData to output all current known types
-Revision 1.215 2003/07/13 02:28:00 cheshire
-<rdar://problem/3325166> SendResponses didn't all its responses
-Delete all references to RRInterfaceActive -- it's now superfluous
+Revision 1.639 2007/05/23 00:51:33 cheshire
+Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
+each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
+days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
-Revision 1.214 2003/07/13 01:47:53 cheshire
-Fix one error and one warning in the Windows build
+Revision 1.638 2007/05/23 00:43:16 cheshire
+If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
-Revision 1.213 2003/07/12 04:25:48 cheshire
-Fix minor signed/unsigned warnings
+Revision 1.637 2007/05/14 23:53:00 cheshire
+Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
-Revision 1.212 2003/07/12 01:59:11 cheshire
-Minor changes to debugf messages
+Revision 1.636 2007/05/10 23:27:15 cheshire
+Update mDNS_Deregister_internal debugging messages
-Revision 1.211 2003/07/12 01:47:01 cheshire
-<rdar://problem/3324495> After name conflict, appended number should be higher than previous number
+Revision 1.635 2007/05/07 20:43:45 cheshire
+<rdar://problem/4241419> Reduce the number of queries and announcements
-Revision 1.210 2003/07/12 01:43:28 cheshire
-<rdar://problem/3324795> Duplicate query suppression not working right
-The correct cutoff time for duplicate query suppression is timenow less one-half the query interval.
-The code was incorrectly using the last query time plus one-half the query interval.
-This was only correct in the case where query acceleration was not in effect.
+Revision 1.634 2007/05/04 22:09:08 cheshire
+Only do "restarting exponential backoff sequence" for mDNS questions
+In mDNS_RegisterInterface, only retrigger mDNS questions
+In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
-Revision 1.209 2003/07/12 01:27:50 cheshire
-<rdar://problem/3320079> Hostname conflict naming should not use two hyphens
-Fix missing "-1" in RemoveLabelSuffix()
+Revision 1.633 2007/05/04 21:45:12 cheshire
+Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
-Revision 1.208 2003/07/11 01:32:38 cheshire
-Syntactic cleanup (no change to funcationality): Now that we only have one host name,
-rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
+Revision 1.632 2007/05/04 20:20:50 cheshire
+<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
+Need to set srs->nta = mDNSNULL; when regState_NoTarget
-Revision 1.207 2003/07/11 01:28:00 cheshire
-<rdar://problem/3161289> No more local.arpa
+Revision 1.631 2007/05/04 00:39:42 cheshire
+<rdar://problem/4410011> Eliminate looping SOA lookups
+When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
+each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
-Revision 1.206 2003/07/11 00:45:02 cheshire
-<rdar://problem/3321909> Client should get callback confirming successful host name registration
+Revision 1.630 2007/05/03 22:40:38 cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-Revision 1.205 2003/07/11 00:40:18 cheshire
-Tidy up debug message in HostNameCallback()
+Revision 1.629 2007/05/03 00:15:51 cheshire
+<rdar://problem/4410011> Eliminate looping SOA lookups
-Revision 1.204 2003/07/11 00:20:32 cheshire
-<rdar://problem/3320087> mDNSResponder should log a message after 16 unsuccessful probes
+Revision 1.628 2007/05/02 22:21:33 cheshire
+<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-Revision 1.203 2003/07/10 23:53:41 cheshire
-<rdar://problem/3320079> Hostname conflict naming should not use two hyphens
+Revision 1.627 2007/04/30 19:29:13 cheshire
+Fix display of port number in "Updating DNS Server" message
-Revision 1.202 2003/07/04 02:23:20 cheshire
-<rdar://problem/3311955> Responder too aggressive at flushing stale data
-Changed mDNSResponder to require four unanswered queries before purging a record, instead of two.
+Revision 1.626 2007/04/30 04:21:13 cheshire
+Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
-Revision 1.201 2003/07/04 01:09:41 cheshire
-<rdar://problem/3315775> Need to implement subtype queries
-Modified ConstructServiceName() to allow three-part service types
+Revision 1.625 2007/04/28 01:34:21 cheshire
+Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
+(Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
-Revision 1.200 2003/07/03 23:55:26 cheshire
-Minor change to wording of syslog warning messages
+Revision 1.624 2007/04/27 21:04:30 cheshire
+On network configuration change, need to call uDNS_RegisterSearchDomains
-Revision 1.199 2003/07/03 23:51:13 cheshire
-<rdar://problem/3315652>: Lots of "have given xxx answers" syslog warnings
-Added more detailed debugging information
+Revision 1.623 2007/04/27 19:28:01 cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
-Revision 1.198 2003/07/03 22:19:30 cheshire
-<rdar://problem/3314346> Bug fix in 3274153 breaks TiVo
-Make exception to allow _tivo_servemedia._tcp.
+Revision 1.622 2007/04/26 16:09:22 cheshire
+mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
-Revision 1.197 2003/07/02 22:33:05 cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
-Minor refinements:
-When cache is exhausted, verify that rrcache_totalused == rrcache_size and report if not
-Allow cache to grow to 512 records before considering it a potential denial-of-service attack
+Revision 1.621 2007/04/26 15:43:22 cheshire
+Make sure DNSServer *s is non-null before using value in LogOperation
-Revision 1.196 2003/07/02 21:19:45 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+Revision 1.620 2007/04/26 13:11:05 cheshire
+Fixed crash when logging out of VPN
-Revision 1.195 2003/07/02 19:56:58 cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
-Minor refinement: m->rrcache_active was not being decremented when
-an active record was deleted because its TTL expired
+Revision 1.619 2007/04/26 00:35:15 cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
-Revision 1.194 2003/07/02 18:47:40 cheshire
-Minor wording change to log messages
+Revision 1.618 2007/04/25 19:26:01 cheshire
+m->NextScheduledQuery was getting set too early in SendQueries()
+Improved "SendQueries didn't send all its queries" debugging message
-Revision 1.193 2003/07/02 02:44:13 cheshire
-Fix warning in non-debug build
+Revision 1.617 2007/04/25 17:48:22 cheshire
+Update debugging message
-Revision 1.192 2003/07/02 02:41:23 cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
+Revision 1.616 2007/04/25 16:38:32 cheshire
+If negative cache entry already exists, reactivate it instead of creating a new one
-Revision 1.191 2003/07/02 02:30:51 cheshire
-HashSlot() returns an array index. It can't be negative; hence it should not be signed.
+Revision 1.615 2007/04/25 02:14:38 cheshire
+<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
+Additional fixes to make LLQs work properly
-Revision 1.190 2003/06/27 00:03:05 vlubet
-<rdar://problem/3304625> Merge of build failure fix for gcc 3.3
+Revision 1.614 2007/04/23 21:52:45 cheshire
+<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
-Revision 1.189 2003/06/11 19:24:03 cheshire
-<rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
-Slight refinement to previous checkin
+Revision 1.613 2007/04/23 04:58:20 cheshire
+<rdar://problem/5072548> Crash when setting extremely large TXT records
-Revision 1.188 2003/06/10 20:33:28 cheshire
-<rdar://problem/3287141> Crash in SendQueries/SendResponses when no active interfaces
+Revision 1.612 2007/04/22 20:39:38 cheshire
+<rdar://problem/4633194> Add 20 to 120ms random delay to browses
-Revision 1.187 2003/06/10 04:30:44 cheshire
-<rdar://problem/3286234> Need to re-probe/re-announce on configuration change
-Only interface-specific records were re-probing and re-announcing, not non-specific records.
+Revision 1.611 2007/04/22 18:16:29 cheshire
+Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
-Revision 1.186 2003/06/10 04:24:39 cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
-Some additional refinements:
-Don't try to do this for unicast-response queries
-better tracking of Qs and KAs in multi-packet KA lists
+Revision 1.610 2007/04/22 06:02:02 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.185 2003/06/10 03:52:49 cheshire
-Update comments and debug messages
+Revision 1.609 2007/04/20 21:17:24 cheshire
+For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-Revision 1.184 2003/06/10 02:26:39 cheshire
-<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
-Make mDNS_Reconfirm() call mDNS_Lock(), like the other API routines
+Revision 1.608 2007/04/20 19:45:31 cheshire
+In LogAllOperations mode, dump out unknown DNS packets in their entirety
-Revision 1.183 2003/06/09 18:53:13 cheshire
-Simplify some debugf() statements (replaced block of 25 lines with 2 lines)
+Revision 1.607 2007/04/19 23:56:25 cheshire
+Don't do cache-flush processing for LLQ answers
-Revision 1.182 2003/06/09 18:38:42 cheshire
-<rdar://problem/3285082> Need to be more tolerant when there are mDNS proxies on the network
-Only issue a correction if the TTL in the proxy packet is less than half the correct value.
+Revision 1.606 2007/04/19 22:50:53 cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
-Revision 1.181 2003/06/07 06:45:05 cheshire
-<rdar://problem/3283666> No need for multiple machines to all be sending the same queries
+Revision 1.605 2007/04/19 20:06:41 cheshire
+Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
-Revision 1.180 2003/06/07 06:31:07 cheshire
-Create little four-line helper function "FindIdenticalRecordInCache()"
+Revision 1.604 2007/04/19 18:03:04 cheshire
+Add "const" declaration
-Revision 1.179 2003/06/07 06:28:13 cheshire
-For clarity, change name of "DNSQuestion q" to "DNSQuestion pktq"
+Revision 1.603 2007/04/06 21:00:25 cheshire
+Fix log message typo
-Revision 1.178 2003/06/07 06:25:12 cheshire
-Update some comments
+Revision 1.602 2007/04/05 22:55:35 cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-Revision 1.177 2003/06/07 04:50:53 cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
+Revision 1.601 2007/04/04 21:48:52 cheshire
+<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-Revision 1.176 2003/06/07 04:33:26 cheshire
-<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
-Minor change: Increment/decrement logic for q->CurrentAnswers should be in
-CacheRecordAdd() and CacheRecordRmv(), not AnswerQuestionWithResourceRecord()
-
-Revision 1.175 2003/06/07 04:11:52 cheshire
-Minor changes to comments and debug messages
-
-Revision 1.174 2003/06/07 01:46:38 cheshire
-<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
-
-Revision 1.173 2003/06/07 01:22:13 cheshire
-<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
-
-Revision 1.172 2003/06/07 00:59:42 cheshire
-<rdar://problem/3283454> Need some randomness to spread queries on the network
-
-Revision 1.171 2003/06/06 21:41:10 cheshire
-For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
-
-Revision 1.170 2003/06/06 21:38:55 cheshire
-Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
-already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
-
-Revision 1.169 2003/06/06 21:35:55 cheshire
-Fix mis-named macro: GetRRHostNameTarget is really GetRRDomainNameTarget
-(the target is a domain name, but not necessarily a host name)
-
-Revision 1.168 2003/06/06 21:33:31 cheshire
-Instead of using (mDNSPlatformOneSecond/2) all over the place, define a constant "InitialQuestionInterval"
-
-Revision 1.167 2003/06/06 21:30:42 cheshire
-<rdar://problem/3282962> Don't delay queries for shared record types
-
-Revision 1.166 2003/06/06 17:20:14 cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
-
-Revision 1.165 2003/06/04 02:53:21 cheshire
-Add some "#pragma warning" lines so it compiles clean on Microsoft compilers
-
-Revision 1.164 2003/06/04 01:25:33 cheshire
-<rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
-Display time interval between first and subsequent queries
-
-Revision 1.163 2003/06/03 19:58:14 cheshire
-<rdar://problem/3277665> mDNS_DeregisterService() fixes:
-When forcibly deregistering after a conflict, ensure we don't send an incorrect goodbye packet.
-Guard against a couple of possible mDNS_DeregisterService() race conditions.
-
-Revision 1.162 2003/06/03 19:30:39 cheshire
-Minor addition refinements for
-<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
-
-Revision 1.161 2003/06/03 18:29:03 cheshire
-Minor changes to comments and debugf() messages
-
-Revision 1.160 2003/06/03 05:02:16 cheshire
-<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
-
-Revision 1.159 2003/06/03 03:31:57 cheshire
-<rdar://problem/3277033> False self-conflict when there are duplicate registrations on one machine
-
-Revision 1.158 2003/06/02 22:57:09 cheshire
-Minor clarifying changes to comments and log messages;
-IdenticalResourceRecordAnyInterface() is really more accurately called just IdenticalResourceRecord()
-
-Revision 1.157 2003/05/31 00:09:49 cheshire
-<rdar://problem/3274862> Add ability to discover what services are on a network
-
-Revision 1.156 2003/05/30 23:56:49 cheshire
-<rdar://problem/3274847> Crash after error in mDNS_RegisterService()
-Need to set "sr->Extras = mDNSNULL" before returning
-
-Revision 1.155 2003/05/30 23:48:00 cheshire
-<rdar://problem/3274832> Announcements not properly grouped
-Due to inconsistent setting of rr->LastAPTime at different places in the
-code, announcements were not properly grouped into a single packet.
-Fixed by creating a single routine called InitializeLastAPTime().
-
-Revision 1.154 2003/05/30 23:38:14 cheshire
-<rdar://problem/3274814> Fix error in IPv6 reverse-mapping PTR records
-Wrote buffer[32] where it should have said buffer[64]
-
-Revision 1.153 2003/05/30 19:10:56 cheshire
-<rdar://problem/3274153> ConstructServiceName needs to be more restrictive
-
-Revision 1.152 2003/05/29 22:39:16 cheshire
-<rdar://problem/3273209> Don't truncate strings in the middle of a UTF-8 character
-
-Revision 1.151 2003/05/29 06:35:42 cheshire
-<rdar://problem/3272221> mDNSCoreReceiveResponse() purging wrong record
-
-Revision 1.150 2003/05/29 06:25:45 cheshire
-<rdar://problem/3272218> Need to call CheckCacheExpiration() *before* AnswerNewQuestion()
-
-Revision 1.149 2003/05/29 06:18:39 cheshire
-<rdar://problem/3272217> Split AnswerLocalQuestions into CacheRecordAdd and CacheRecordRmv
-
-Revision 1.148 2003/05/29 06:11:34 cheshire
-<rdar://problem/3272214> Report if there appear to be too many "Resolve" callbacks
-
-Revision 1.147 2003/05/29 06:01:18 cheshire
-Change some debugf() calls to LogMsg() calls to help with debugging
-
-Revision 1.146 2003/05/28 21:00:44 cheshire
-Re-enable "immediate answer burst" debugf message
-
-Revision 1.145 2003/05/28 20:57:44 cheshire
-<rdar://problem/3271550> mDNSResponder reports "Cannot perform multi-packet
-known-answer suppression ..." This is a known issue caused by a bug in the OS X 10.2
-version of mDNSResponder, so for now we should suppress this warning message.
-
-Revision 1.144 2003/05/28 18:05:12 cheshire
-<rdar://problem/3009899> mDNSResponder allows invalid service registrations
-Fix silly mistake: old logic allowed "TDP" and "UCP" as valid names
-
-Revision 1.143 2003/05/28 04:31:29 cheshire
-<rdar://problem/3270733> mDNSResponder not sending probes at the prescribed time
-
-Revision 1.142 2003/05/28 03:13:07 cheshire
-<rdar://problem/3009899> mDNSResponder allows invalid service registrations
-Require that the transport protocol be _udp or _tcp
-
-Revision 1.141 2003/05/28 02:19:12 cheshire
-<rdar://problem/3270634> Misleading messages generated by iChat
-Better fix: Only generate the log message for queries where the TC bit is set.
-
-Revision 1.140 2003/05/28 01:55:24 cheshire
-Minor change to log messages
-
-Revision 1.139 2003/05/28 01:52:51 cheshire
-<rdar://problem/3270634> Misleading messages generated by iChat
-
-Revision 1.138 2003/05/27 22:35:00 cheshire
-<rdar://problem/3270277> mDNS_RegisterInterface needs to retrigger questions
-
-Revision 1.137 2003/05/27 20:04:33 cheshire
-<rdar://problem/3269900> mDNSResponder crash in mDNS_vsnprintf()
-
-Revision 1.136 2003/05/27 18:50:07 cheshire
-<rdar://problem/3269768> mDNS_StartResolveService doesn't inform client of port number changes
-
-Revision 1.135 2003/05/26 04:57:28 cheshire
-<rdar://problem/3268953> Delay queries when there are already answers in the cache
-
-Revision 1.134 2003/05/26 04:54:54 cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-Accidentally deleted '%' case from the switch statement
-
-Revision 1.133 2003/05/26 03:21:27 cheshire
-Tidy up address structure naming:
-mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.132 2003/05/26 03:01:26 cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.131 2003/05/26 00:42:05 cheshire
-<rdar://problem/3268876> Temporarily include mDNSResponder version in packets
-
-Revision 1.130 2003/05/24 16:39:48 cheshire
-<rdar://problem/3268631> SendResponses also needs to handle multihoming better
-
-Revision 1.129 2003/05/23 02:15:37 cheshire
-Fixed misleading use of the term "duplicate suppression" where it should have
-said "known answer suppression". (Duplicate answer suppression is something
-different, and duplicate question suppression is yet another thing, so the use
-of the completely vague term "duplicate suppression" was particularly bad.)
-
-Revision 1.128 2003/05/23 01:55:13 cheshire
-<rdar://problem/3267127> After name change, mDNSResponder needs to re-probe for name uniqueness
+Revision 1.600 2007/04/04 01:31:33 cheshire
+Improve debugging message
-Revision 1.127 2003/05/23 01:02:15 ksekar
-<rdar://problem/3032577>: mDNSResponder needs to include unique id in default name
+Revision 1.599 2007/04/04 00:03:26 cheshire
+<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-Revision 1.126 2003/05/22 02:29:22 cheshire
-<rdar://problem/2984918> SendQueries needs to handle multihoming better
-Complete rewrite of SendQueries. Works much better now :-)
+Revision 1.598 2007/04/03 19:43:16 cheshire
+Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
-Revision 1.125 2003/05/22 01:50:45 cheshire
-Fix warnings, and improve log messages
+Revision 1.597 2007/03/31 00:32:32 cheshire
+After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
-Revision 1.124 2003/05/22 01:41:50 cheshire
-DiscardDeregistrations doesn't need InterfaceID parameter
+Revision 1.596 2007/03/28 20:59:26 cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-Revision 1.123 2003/05/22 01:38:55 cheshire
-Change bracketing of #pragma mark
+Revision 1.595 2007/03/26 23:48:16 cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
+Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
-Revision 1.122 2003/05/21 19:59:04 cheshire
-<rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
-Minor refinements; make sure we don't truncate in the middle of a multi-byte UTF-8 character
+Revision 1.594 2007/03/26 23:05:05 cheshire
+<rdar://problem/5089257> Don't cache TSIG records
-Revision 1.121 2003/05/21 17:54:07 ksekar
-<rdar://problem/3148431> ER: Tweak responder's default name conflict behavior
-New rename behavior - domain name "foo" becomes "foo--2" on conflict, richtext name becomes "foo (2)"
+Revision 1.593 2007/03/23 17:40:08 cheshire
+<rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
-Revision 1.120 2003/05/19 22:14:14 ksekar
-<rdar://problem/3162914> mDNS probe denials/conflicts not detected unless conflict is of the same type
+Revision 1.592 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-Revision 1.119 2003/05/16 01:34:10 cheshire
-Fix some warnings
+Revision 1.591 2007/03/22 00:49:19 cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
-Revision 1.118 2003/05/14 18:48:40 cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-More minor refinements:
-mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
-mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
+Revision 1.590 2007/03/21 23:05:59 cheshire
+Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
-Revision 1.117 2003/05/14 07:08:36 cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
+Revision 1.589 2007/03/20 15:37:19 cheshire
+Delete unnecessary log message
-Revision 1.116 2003/05/14 06:51:56 cheshire
-<rdar://problem/3027144> mDNSResponder doesn't refresh server info if changed during sleep
+Revision 1.588 2007/03/20 00:24:44 cheshire
+<rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
-Revision 1.115 2003/05/14 06:44:31 cheshire
-Improve debugging message
+Revision 1.587 2007/03/16 22:10:56 cheshire
+<rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
-Revision 1.114 2003/05/07 01:47:03 cheshire
-<rdar://problem/3250330> Also protect against NULL domainlabels
+Revision 1.586 2007/03/10 03:26:44 cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Revision 1.113 2003/05/07 00:28:18 cheshire
-<rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
+Revision 1.585 2007/03/10 02:02:58 cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
+Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
-Revision 1.112 2003/05/06 00:00:46 cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
+Revision 1.584 2007/02/28 01:51:27 cheshire
+Added comment about reverse-order IP address
-Revision 1.111 2003/05/05 23:42:08 cheshire
-<rdar://problem/3245631> Resolves never succeed
-Was setting "rr->LastAPTime = timenow - rr->LastAPTime"
-instead of "rr->LastAPTime = timenow - rr->ThisAPInterval"
+Revision 1.583 2007/01/27 03:19:33 cheshire
+Need to initialize question->sock
-Revision 1.110 2003/04/30 21:09:59 cheshire
-<rdar://problem/3244727> mDNS_vsnprintf needs to be more defensive against invalid domain names
+Revision 1.582 2007/01/25 00:40:16 cheshire
+Unified CNAME-following functionality into cache management code (which means CNAME-following
+should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
-Revision 1.109 2003/04/26 02:41:56 cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
+Revision 1.581 2007/01/23 02:56:11 cheshire
+Store negative results in the cache, instead of generating them out of pktResponseHndlr()
-Revision 1.108 2003/04/25 01:45:56 cheshire
-<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
+Revision 1.580 2007/01/19 21:17:33 cheshire
+StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
-Revision 1.107 2003/04/25 00:41:31 cheshire
-<rdar://problem/3239912> Create single routine PurgeCacheResourceRecord(), to avoid bugs in future
+Revision 1.579 2007/01/19 18:39:10 cheshire
+Fix a bunch of parameters that should have been declared "const"
-Revision 1.106 2003/04/22 03:14:45 cheshire
-<rdar://problem/3232229> Include Include instrumented mDNSResponder in panther now
+Revision 1.578 2007/01/10 22:51:57 cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-Revision 1.105 2003/04/22 01:07:43 cheshire
-<rdar://problem/3176248> DNSServiceRegistrationUpdateRecord should support a default ttl
-If TTL parameter is zero, leave record TTL unchanged
+Revision 1.577 2007/01/10 02:05:21 cheshire
+Delay uDNS_SetupDNSConfig() until *after* the platform layer
+has set up the interface list and security credentials
-Revision 1.104 2003/04/21 19:15:52 cheshire
-Fix some compiler warnings
+Revision 1.576 2007/01/09 02:40:57 cheshire
+uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
+moved it to mDNS_Init() in mDNS.c (core code)
-Revision 1.103 2003/04/19 02:26:35 cheshire
-<rdar://problem/3233804> Incorrect goodbye packet after conflict
+Revision 1.575 2007/01/09 00:17:25 cheshire
+Improve "ERROR m->CurrentRecord already set" debugging messages
-Revision 1.102 2003/04/17 03:06:28 cheshire
-<rdar://problem/3231321> No need to query again when a service goes away
-Set UnansweredQueries to 2 when receiving a "goodbye" packet
+Revision 1.574 2007/01/05 08:30:41 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.101 2003/04/15 20:58:31 jgraessl
-<rdar://problem/3229014> Added a hash to lookup records in the cache.
+Revision 1.573 2007/01/05 06:34:03 cheshire
+Improve "ERROR m->CurrentQuestion already set" debugging messages
-Revision 1.100 2003/04/15 18:53:14 cheshire
-<rdar://problem/3229064> Bug in ScheduleNextTask
-mDNS.c 1.94 incorrectly combined two "if" statements into one.
+Revision 1.572 2007/01/04 23:11:11 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-Revision 1.99 2003/04/15 18:09:13 jgraessl
-<rdar://problem/3228892>
-Reviewed by: Stuart Cheshire
-Added code to keep track of when the next cache item will expire so we can
-call TidyRRCache only when necessary.
+Revision 1.571 2007/01/04 21:45:20 cheshire
+Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
+to do additional lock sanity checking around callback invocations
-Revision 1.98 2003/04/03 03:43:55 cheshire
-<rdar://problem/3216837> Off-by-one error in probe rate limiting
+Revision 1.570 2007/01/04 20:57:47 cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-Revision 1.97 2003/04/02 01:48:17 cheshire
-<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
-Additional fix pointed out by Josh:
-Also set ProbeFailTime when incrementing NumFailedProbes when resetting a record back to probing state
+Revision 1.569 2007/01/04 20:27:27 cheshire
+Change a LogMsg() to debugf()
-Revision 1.96 2003/04/01 23:58:55 cheshire
-Minor comment changes
+Revision 1.568 2007/01/04 02:39:53 cheshire
+<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
-Revision 1.95 2003/04/01 23:46:05 cheshire
-<rdar://problem/3214832> mDNSResponder can get stuck in infinite loop after many location cycles
-mDNS_DeregisterInterface() flushes the RR cache by marking all records received on that interface
-to expire in one second. However, if a mDNS_StartResolveService() call is made in that one-second
-window, it can get an SRV answer from one of those soon-to-be-deleted records, resulting in
-FoundServiceInfoSRV() making an interface-specific query on the interface that was just removed.
+Revision 1.567 2006/12/21 00:01:37 cheshire
+Tidy up code alignment
-Revision 1.94 2003/03/29 01:55:19 cheshire
-<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
-Solution: Major cleanup of packet timing and conflict handling rules
+Revision 1.566 2006/12/20 04:07:34 cheshire
+Remove uDNS_info substructure from AuthRecord_struct
-Revision 1.93 2003/03/28 01:54:36 cheshire
-Minor tidyup of IPv6 (AAAA) code
+Revision 1.565 2006/12/19 22:49:23 cheshire
+Remove uDNS_info substructure from ServiceRecordSet_struct
-Revision 1.92 2003/03/27 03:30:55 cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use DeadvertiseInterface() instead
- (it never really needed to deregister the interface at all)
+Revision 1.564 2006/12/19 02:38:20 cheshire
+Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
-Revision 1.91 2003/03/15 04:40:36 cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
+Revision 1.563 2006/12/19 02:18:48 cheshire
+Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
-Revision 1.90 2003/03/14 20:26:37 cheshire
-Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
+Revision 1.562 2006/12/16 01:58:31 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
-Revision 1.89 2003/03/12 19:57:50 cheshire
-Fixed typo in debug message
+Revision 1.561 2006/12/01 07:38:53 herscher
+Only perform cache workaround fix if query is wide-area
-Revision 1.88 2003/03/12 00:17:44 cheshire
-<rdar://problem/3195426> GetFreeCacheRR needs to be more willing to throw away recent records
+Revision 1.560 2006/11/30 23:07:56 herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-Revision 1.87 2003/03/11 01:27:20 cheshire
-Reduce debugging messages (reclassify some "debugf" as "verbosedebugf")
+Revision 1.559 2006/11/27 08:20:57 cheshire
+Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
-Revision 1.86 2003/03/06 20:44:33 cheshire
-Comment tidyup
+Revision 1.558 2006/11/10 07:44:03 herscher
+<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-Revision 1.85 2003/03/05 03:38:35 cheshire
-<rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
-Fixed by leaving client in list after conflict, until client explicitly deallocates
+Revision 1.557 2006/11/10 01:12:51 cheshire
+<rdar://problem/4829718> Incorrect TTL corrections
-Revision 1.84 2003/03/05 01:27:30 cheshire
-<rdar://problem/3185482> Different TTL for multicast versus unicast responses
-When building unicast responses, record TTLs are capped to 10 seconds
+Revision 1.556 2006/11/10 00:54:14 cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
-Revision 1.83 2003/03/04 23:48:52 cheshire
-<rdar://problem/3188865> Double probes after wake from sleep
-Don't reset record type to kDNSRecordTypeUnique if record is DependentOn another
+Revision 1.555 2006/10/30 20:03:37 cheshire
+<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
-Revision 1.82 2003/03/04 23:38:29 cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Only set rr->CRActiveQuestion to point to the
-currently active representative of a question set
+Revision 1.554 2006/10/20 05:35:04 herscher
+<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-Revision 1.81 2003/02/21 03:35:34 cheshire
-<rdar://problem/3179007> mDNSResponder needs to include AAAA records in additional answer section
+Revision 1.553 2006/10/05 03:42:43 herscher
+Remove embedded uDNS_info struct in DNSQuestion_struct
-Revision 1.80 2003/02/21 02:47:53 cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Several places in the code were calling CacheRRActive(), which searched the entire
-question list every time, to see if this cache resource record answers any question.
-Instead, we now have a field "CRActiveQuestion" in the resource record structure
+Revision 1.552 2006/09/15 21:20:15 cheshire
+Remove uDNS_info substructure from mDNS_struct
-Revision 1.79 2003/02/21 01:54:07 cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
+Revision 1.551 2006/08/14 23:24:22 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.78 2003/02/20 06:48:32 cheshire
-<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
+Revision 1.550 2006/07/27 17:58:34 cheshire
+Improved text of "SendQueries didn't send all its queries; will try again" debugging message
-Revision 1.77 2003/01/31 03:35:59 cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-When there were *two* active questions in the list, they were incorrectly
-finding *each other* and *both* being marked as duplicates of another question
+Revision 1.549 2006/07/20 22:07:31 mkrochma
+<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
+More fixes for uninitialized variables
-Revision 1.76 2003/01/29 02:46:37 cheshire
-Fix for IPv6:
-A physical interface is identified solely by its InterfaceID (not by IP and type).
-On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
-In cases where the requested outbound protocol (v4 or v6) is not supported on
-that InterfaceID, the platform support layer should simply discard that packet.
+Revision 1.548 2006/07/20 19:30:19 mkrochma
+<rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
-Revision 1.75 2003/01/29 01:47:40 cheshire
-Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
+Revision 1.547 2006/07/15 02:31:30 cheshire
+<rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
-Revision 1.74 2003/01/28 05:26:25 cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-Add 'Active' flag for interfaces
-
-Revision 1.73 2003/01/28 03:45:12 cheshire
-Fixed missing "not" in "!mDNSAddrIsDNSMulticast(dstaddr)"
+Revision 1.546 2006/07/07 01:09:09 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-Revision 1.72 2003/01/28 01:49:48 cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-FindDuplicateQuestion() was incorrectly finding the question itself in the list,
-and incorrectly marking it as a duplicate (of itself), so that it became inactive.
-
-Revision 1.71 2003/01/28 01:41:44 cheshire
-<rdar://problem/3153091> Race condition when network change causes bad stuff
-When an interface goes away, interface-specific questions on that interface become orphaned.
-Orphan questions cause HaveQueries to return true, but there's no interface to send them on.
-Fix: mDNS_DeregisterInterface() now calls DeActivateInterfaceQuestions()
+Revision 1.545 2006/07/05 23:10:30 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-Revision 1.70 2003/01/23 19:00:20 cheshire
-Protect against infinite loops in mDNS_Execute
+Revision 1.544 2006/06/29 07:42:14 cheshire
+<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-Revision 1.69 2003/01/21 22:56:32 jgraessl
-<rdar://problem/3124348> service name changes are not properly handled
-Submitted by: Stuart Cheshire
-Reviewed by: Joshua Graessley
-Applying changes for 3124348 to main branch. 3124348 changes went in to a
-branch for SU.
+Revision 1.543 2006/06/29 01:38:43 cheshire
+<rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
-Revision 1.68 2003/01/17 04:09:27 cheshire
-<rdar://problem/3141038> mDNSResponder Resolves are unreliable on multi-homed hosts
+Revision 1.542 2006/06/27 23:40:29 cheshire
+Fix typo in comment: mis-spelled "compile"
-Revision 1.67 2003/01/17 03:56:45 cheshire
-Default 24-hour TTL is far too long. Changing to two hours.
+Revision 1.541 2006/06/27 19:46:24 cheshire
+Updated comments and debugging messages
-Revision 1.66 2003/01/13 23:49:41 jgraessl
-Merged changes for the following fixes in to top of tree:
-<rdar://problem/3086540> computer name changes not handled properly
-<rdar://problem/3124348> service name changes are not properly handled
-<rdar://problem/3124352> announcements sent in pairs, failing chattiness test
+Revision 1.540 2006/06/15 21:35:16 cheshire
+Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
+from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
-Revision 1.65 2002/12/23 22:13:28 jgraessl
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
+Revision 1.539 2006/06/08 23:45:46 cheshire
+Change SimultaneousProbe messages from debugf() to LogOperation()
-Revision 1.64 2002/11/26 20:49:06 cheshire
-<rdar://problem/3104543> RFC 1123 allows the first character of a name label to be either a letter or a digit
+Revision 1.538 2006/03/19 17:13:06 cheshire
+<rdar://problem/4483117> Need faster purging of stale records
+Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
+and reconfirm whole chain of antecedents ot once
-Revision 1.63 2002/09/21 20:44:49 zarzycki
-Added APSL info
+Revision 1.537 2006/03/19 02:00:07 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-Revision 1.62 2002/09/20 03:25:37 cheshire
-Fix some compiler warnings
+Revision 1.536 2006/03/08 23:29:53 cheshire
+<rdar://problem/4468716> Improve "Service Renamed" log message
-Revision 1.61 2002/09/20 01:05:24 cheshire
-Don't kill the Extras list in mDNS_DeregisterService()
-
-Revision 1.60 2002/09/19 23:47:35 cheshire
-Added mDNS_RegisterNoSuchService() function for assertion of non-existence
-of a particular named service
-
-Revision 1.59 2002/09/19 21:25:34 cheshire
-mDNS_snprintf() doesn't need to be in a separate file
+Revision 1.535 2006/03/02 20:41:17 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Minor code tidying and comments to reduce the risk of similar programming errors in future
-Revision 1.58 2002/09/19 04:20:43 cheshire
-Remove high-ascii characters that confuse some systems
+Revision 1.534 2006/03/02 03:25:46 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
-Revision 1.57 2002/09/17 01:07:08 cheshire
-Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
+Revision 1.533 2006/02/26 00:54:41 cheshire
+Fixes to avoid code generation warning/error on FreeBSD 7
-Revision 1.56 2002/09/16 19:44:17 cheshire
-Merge in license terms from Quinn's copy, in preparation for Darwin release
*/
#include "DNSCommon.h" // Defines general DNS untility routines
#include "uDNS.h" // Defines entry points into unicast-specific routines
+
// Disable certain benign warnings with Microsoft compilers
#if(defined(_MSC_VER))
// Disable "conditional expression is constant" warning for debug macros.
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
#pragma mark - Program Constants
#endif
-mDNSexport const mDNSIPPort zeroIPPort = { { 0 } };
-mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } };
-mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } };
-mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } };
-mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } };
-mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
-mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} };
-
-mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0;
-mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1;
-
-mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
-
-#define UnicastDNSPortAsNumber 53
-#define NATPMPPortAsNumber 5351
-#define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
-#define MulticastDNSPortAsNumber 5353
-#define LoopbackIPCPortAsNumber 5354
-
-mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } };
-mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } };
-mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } };
-mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
-mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } };
-
-mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } };
-mDNSexport const mDNSv4Addr AllDNSLinkGroupv4 = { { 224, 0, 0, 251 } };
-mDNSexport const mDNSv6Addr AllDNSLinkGroupv6 = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } };
-mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } };
-mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
-
-mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
-mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } };
-mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
-mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
-mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
-mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
+#define NO_HINFO 1
+
+mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
// Any records bigger than this are considered 'large' records
#define SmallRecordLimit 1024
{
"b._dns-sd._udp.", // Browse
"db._dns-sd._udp.", // Default Browse
- "lb._dns-sd._udp.", // Legacy Browse
+ "lb._dns-sd._udp.", // Automatic Browse
"r._dns-sd._udp.", // Registration
"dr._dns-sd._udp." // Default Registration
};
#define uDNS_IsActiveQuery(q, u) mDNSfalse
#endif
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Specialized mDNS version of vsnprintf
-#endif
-
-static const struct mDNSprintf_format
- {
- unsigned leftJustify : 1;
- unsigned forceSign : 1;
- unsigned zeroPad : 1;
- unsigned havePrecision : 1;
- unsigned hSize : 1;
- unsigned lSize : 1;
- char altForm;
- char sign; // +, - or space
- unsigned int fieldWidth;
- unsigned int precision;
- } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
- {
- mDNSu32 nwritten = 0;
- int c;
- if (buflen == 0) return(0);
- buflen--; // Pre-reserve one space in the buffer for the terminating null
- if (buflen == 0) goto exit;
-
- for (c = *fmt; c != 0; c = *++fmt)
- {
- if (c != '%')
- {
- *sbuffer++ = (char)c;
- if (++nwritten >= buflen) goto exit;
- }
- else
- {
- unsigned int i=0, j;
- // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
- // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
- // The size needs to be enough for a 256-byte domain name plus some error text.
- #define mDNS_VACB_Size 300
- char mDNS_VACB[mDNS_VACB_Size];
- #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
- #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
- char *s = mDNS_VACB_Lim, *digits;
- struct mDNSprintf_format F = mDNSprintf_format_default;
-
- while (1) // decode flags
- {
- c = *++fmt;
- if (c == '-') F.leftJustify = 1;
- else if (c == '+') F.forceSign = 1;
- else if (c == ' ') F.sign = ' ';
- else if (c == '#') F.altForm++;
- else if (c == '0') F.zeroPad = 1;
- else break;
- }
-
- if (c == '*') // decode field width
- {
- int f = va_arg(arg, int);
- if (f < 0) { f = -f; F.leftJustify = 1; }
- F.fieldWidth = (unsigned int)f;
- c = *++fmt;
- }
- else
- {
- for (; c >= '0' && c <= '9'; c = *++fmt)
- F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
- }
-
- if (c == '.') // decode precision
- {
- if ((c = *++fmt) == '*')
- { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
- else for (; c >= '0' && c <= '9'; c = *++fmt)
- F.precision = (10 * F.precision) + (c - '0');
- F.havePrecision = 1;
- }
-
- if (F.leftJustify) F.zeroPad = 0;
-
- conv:
- switch (c) // perform appropriate conversion
- {
- unsigned long n;
- case 'h' : F.hSize = 1; c = *++fmt; goto conv;
- case 'l' : // fall through
- case 'L' : F.lSize = 1; c = *++fmt; goto conv;
- case 'd' :
- case 'i' : if (F.lSize) n = (unsigned long)va_arg(arg, long);
- else n = (unsigned long)va_arg(arg, int);
- if (F.hSize) n = (short) n;
- if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
- else if (F.forceSign) F.sign = '+';
- goto decimal;
- case 'u' : if (F.lSize) n = va_arg(arg, unsigned long);
- else n = va_arg(arg, unsigned int);
- if (F.hSize) n = (unsigned short) n;
- F.sign = 0;
- goto decimal;
- decimal: if (!F.havePrecision)
- {
- if (F.zeroPad)
- {
- F.precision = F.fieldWidth;
- if (F.sign) --F.precision;
- }
- if (F.precision < 1) F.precision = 1;
- }
- if (F.precision > mDNS_VACB_Size - 1)
- F.precision = mDNS_VACB_Size - 1;
- for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
- for (; i < F.precision; i++) *--s = '0';
- if (F.sign) { *--s = F.sign; i++; }
- break;
-
- case 'o' : if (F.lSize) n = va_arg(arg, unsigned long);
- else n = va_arg(arg, unsigned int);
- if (F.hSize) n = (unsigned short) n;
- if (!F.havePrecision)
- {
- if (F.zeroPad) F.precision = F.fieldWidth;
- if (F.precision < 1) F.precision = 1;
- }
- if (F.precision > mDNS_VACB_Size - 1)
- F.precision = mDNS_VACB_Size - 1;
- for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
- if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
- for (; i < F.precision; i++) *--s = '0';
- break;
-
- case 'a' : {
- unsigned char *a = va_arg(arg, unsigned char *);
- if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
- else
- {
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- if (F.altForm)
- {
- mDNSAddr *ip = (mDNSAddr*)a;
- switch (ip->type)
- {
- case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break;
- case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
- default: F.precision = 0; break;
- }
- }
- switch (F.precision)
- {
- case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
- a[0], a[1], a[2], a[3]); break;
- case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
- a[0], a[1], a[2], a[3], a[4], a[5]); break;
- case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
- "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
- a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
- a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
- default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
- "(i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
- }
- }
- }
- break;
-
- case 'p' : F.havePrecision = F.lSize = 1;
- F.precision = 8;
- case 'X' : digits = "0123456789ABCDEF";
- goto hexadecimal;
- case 'x' : digits = "0123456789abcdef";
- hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
- else n = va_arg(arg, unsigned int);
- if (F.hSize) n = (unsigned short) n;
- if (!F.havePrecision)
- {
- if (F.zeroPad)
- {
- F.precision = F.fieldWidth;
- if (F.altForm) F.precision -= 2;
- }
- if (F.precision < 1) F.precision = 1;
- }
- if (F.precision > mDNS_VACB_Size - 1)
- F.precision = mDNS_VACB_Size - 1;
- for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
- for (; i < F.precision; i++) *--s = '0';
- if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
- break;
-
- case 'c' : *--s = (char)va_arg(arg, int); i = 1; break;
-
- case 's' : s = va_arg(arg, char *);
- if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
- else switch (F.altForm)
- {
- case 0: i=0;
- if (!F.havePrecision) // C string
- while(s[i]) i++;
- else
- {
- while ((i < F.precision) && s[i]) i++;
- // Make sure we don't truncate in the middle of a UTF-8 character
- // If last character we got was any kind of UTF-8 multi-byte character,
- // then see if we have to back up.
- // This is not as easy as the similar checks below, because
- // here we can't assume it's safe to examine the *next* byte, so we
- // have to confine ourselves to working only backwards in the string.
- j = i; // Record where we got to
- // Now, back up until we find first non-continuation-char
- while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
- // Now s[i-1] is the first non-continuation-char
- // and (j-i) is the number of continuation-chars we found
- if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char
- {
- i--; // Tentatively eliminate this start-char as well
- // Now (j-i) is the number of characters we're considering eliminating.
- // To be legal UTF-8, the start-char must contain (j-i) one-bits,
- // followed by a zero bit. If we shift it right by (7-(j-i)) bits
- // (with sign extension) then the result has to be 0xFE.
- // If this is right, then we reinstate the tentatively eliminated bytes.
- if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
- }
- }
- break;
- case 1: i = (unsigned char) *s++; break; // Pascal string
- case 2: { // DNS label-sequence name
- unsigned char *a = (unsigned char *)s;
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- if (*a == 0) *s++ = '.'; // Special case for root DNS name
- while (*a)
- {
- if (*a > 63) { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
- if (s + *a >= &mDNS_VACB[254]) { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
- s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%#s.", a);
- a += 1 + *a;
- }
- i = (mDNSu32)(s - mDNS_VACB);
- s = mDNS_VACB; // Reset s back to the start of the buffer
- break;
- }
- }
- // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
- if (F.havePrecision && i > F.precision)
- { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
- break;
-
- case 'n' : s = va_arg(arg, char *);
- if (F.hSize) * (short *) s = (short)nwritten;
- else if (F.lSize) * (long *) s = (long)nwritten;
- else * (int *) s = (int)nwritten;
- continue;
-
- default: s = mDNS_VACB;
- i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
-
- case '%' : *sbuffer++ = (char)c;
- if (++nwritten >= buflen) goto exit;
- break;
- }
-
- if (i < F.fieldWidth && !F.leftJustify) // Pad on the left
- do {
- *sbuffer++ = ' ';
- if (++nwritten >= buflen) goto exit;
- } while (i < --F.fieldWidth);
-
- // Make sure we don't truncate in the middle of a UTF-8 character.
- // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the allowed output. If s[i] is a
- // UTF-8 continuation character, then we've cut a unicode character in half, so back up 'i' until s[i] is no longer a UTF-8 continuation
- // character. (if the input was proprly formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
- if (i > buflen - nwritten)
- { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
- for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result
- nwritten += i;
- if (nwritten >= buflen) goto exit;
-
- for (; i < F.fieldWidth; i++) // Pad on the right
- {
- *sbuffer++ = ' ';
- if (++nwritten >= buflen) goto exit;
- }
- }
- }
- exit:
- *sbuffer++ = 0;
- return(nwritten);
- }
-
-mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
- {
- mDNSu32 length;
-
- va_list ptr;
- va_start(ptr,fmt);
- length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
- va_end(ptr);
-
- return(length);
- }
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#pragma mark - General Utility Functions
#endif
-#define InitialQuestionInterval (mDNSPlatformOneSecond/2)
#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
-mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
+mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
{
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
if (ActiveQuestion(q))
- if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
- m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
+ {
+ mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
+
+ // Don't allow sendtime to be earlier than SuppressStdPort53Queries
+ if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0))
+ sendtime = m->SuppressStdPort53Queries;
+
+ if (m->NextScheduledQuery - sendtime > 0)
+ m->NextScheduledQuery = sendtime;
+ }
}
-mDNSlocal CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
+mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
{
CacheGroup *cg;
for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
if (addr->type == mDNSAddrType_IPv4)
{
- if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue);
+ // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception
+ if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
for (intf = m->HostInterfaces; intf; intf = intf->next)
if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
if (addr->type == mDNSAddrType_IPv6)
{
- if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue);
+ if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue);
for (intf = m->HostInterfaces; intf; intf = intf->next)
if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
return(mDNSfalse);
}
-// Set up a AuthRecord with sensible default values.
-// These defaults may be overwritten with new values before mDNS_Register is called
-mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
- mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
- {
- mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
- // Don't try to store a TTL bigger than we can represent in platform time units
- if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
- ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
- else if (ttl == 0) // And Zero TTL is illegal
- ttl = DefaultTTLforRRType(rrtype);
-
- // Field Group 1: The actual information pertaining to this resource record
- rr->resrec.RecordType = RecordType;
- rr->resrec.InterfaceID = InterfaceID;
- rr->resrec.name = &rr->namestorage;
- rr->resrec.rrtype = rrtype;
- rr->resrec.rrclass = kDNSClass_IN;
- rr->resrec.rroriginalttl = ttl;
-// rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal
-// rr->resrec.rdestimate = set in mDNS_Register_internal
-// rr->resrec.rdata = MUST be set by client
-
- if (RDataStorage)
- rr->resrec.rdata = RDataStorage;
- else
- {
- rr->resrec.rdata = &rr->rdatastorage;
- rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
- }
-
- // Field Group 2: Persistent metadata for Authoritative Records
- rr->Additional1 = mDNSNULL;
- rr->Additional2 = mDNSNULL;
- rr->DependentOn = mDNSNULL;
- rr->RRSet = mDNSNULL;
- rr->RecordCallback = Callback;
- rr->RecordContext = Context;
-
- rr->HostTarget = mDNSfalse;
- rr->AllowRemoteQuery = mDNSfalse;
- rr->ForceMCast = mDNSfalse;
-
- // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
-
- rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register()
- }
-
// For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
// Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
-mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord)
+mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
{
// Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
if (AddRecord) rr->LocalAnswer = mDNStrue;
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- if (q->QuestionCallback)
+ mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
+ if (q->QuestionCallback && !q->NoAnswer)
q->QuestionCallback(m, q, &rr->resrec, AddRecord);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
-// When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers to each,
-// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
+// When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers
+// to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
// If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
// Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
-mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord)
+mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
{
- if (m->CurrentQuestion) LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set");
+ if (m->CurrentQuestion)
+ LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = m->LocalOnlyQuestions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
#define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
-#define InitialAnnounceCount ((mDNSu8)10)
+#define InitialAnnounceCount ((mDNSu8)8)
// Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
// This means that because the announce interval is doubled after sending the first packet, the first
// This is used for cache flush management:
// When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent
// When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed
-mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, const ResourceRecord *const r2)
+
+mDNSlocal mDNSBool SameResourceRecordSignature(const AuthRecord *const r1, const AuthRecord *const r2)
{
if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); }
if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); }
- if (r1->InterfaceID &&
- r2->InterfaceID &&
- r1->InterfaceID != r2->InterfaceID) return(mDNSfalse);
- return(mDNSBool)(r1->rrtype == r2->rrtype && r1->rrclass == r2->rrclass && r1->namehash == r2->namehash && SameDomainName(r1->name, r2->name));
+ if (r1->resrec.InterfaceID &&
+ r2->resrec.InterfaceID &&
+ r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse);
+ return(mDNSBool)(
+ r1->resrec.rrtype == r2->resrec.rrtype &&
+ r1->resrec.rrclass == r2->resrec.rrclass &&
+ r1->resrec.namehash == r2->resrec.namehash &&
+ SameDomainName(r1->resrec.name, r2->resrec.name));
}
// PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
authrr->resrec.InterfaceID &&
pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
- return(mDNSBool)(pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && SameDomainName(pktrr->resrec.name, authrr->resrec.name));
+ return(mDNSBool)(
+ pktrr->resrec.rrclass == authrr->resrec.rrclass &&
+ pktrr->resrec.namehash == authrr->resrec.namehash &&
+ SameDomainName(pktrr->resrec.name, authrr->resrec.name));
}
// IdenticalResourceRecord returns true if two resources records have
// the same name, type, class, and identical rdata (InterfaceID and TTL may differ)
+
+// IdenticalSameNameRecord is the same, except it skips the expensive SameDomainName() check,
+// which is at its most expensive and least useful in cases where we know in advance that the names match
+
mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
{
if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
- if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) return(mDNSfalse);
+ if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
+ return(mDNSfalse);
+ return(SameRData(r1, r2));
+ }
+
+mDNSlocal mDNSBool IdenticalSameNameRecord(const ResourceRecord *const r1, const ResourceRecord *const r2)
+ {
+ if (!r1) { LogMsg("IdenticalSameNameRecord ERROR: r1 is NULL"); return(mDNSfalse); }
+ if (!r2) { LogMsg("IdenticalSameNameRecord ERROR: r2 is NULL"); return(mDNSfalse); }
+ if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass)
+ return(mDNSfalse);
+
+#if VerifySameNameAssumptions
+ if (r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name))
+ {
+ LogMsg("Bogus IdenticalSameNameRecord call: %##s does not match %##s", r1->name->c, r1->name->c);
+ return(mDNSfalse);
+ }
+#endif
+
return(SameRData(r1, r2));
}
{
if (rr->resrec.RecordType == kDNSRecordTypeUnique)
{
- //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
+ //LogMsg("ProbeCount %d Next %ld %s",
+ // rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
}
m->SuppressProbes = m->NextScheduledQuery;
}
- // We announce to flush stale data from other caches. It is a reasonable assumption that any
- // old stale copies will probably have the same TTL we're using, so announcing longer than
- // this serves no purpose -- any stale copies of that record will have expired by then anyway.
- rr->AnnounceUntil = m->timenow + TicksTTL(rr);
rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
// Set LastMCTime to now, to inhibit multicast responses
// (no need to send additional multicast responses when we're announcing anyway)
SetNextAnnounceProbeTime(m, rr);
}
-#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
-
+// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
+// Eventually we should unify this with GetServiceTarget() in uDNS.c
mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
{
domainname *target = GetRRDomainNameTarget(&rr->resrec);
if (target && !SameDomainName(target, &m->MulticastHostname))
{
AssignDomainName(target, &m->MulticastHostname);
- SetNewRData(&rr->resrec, mDNSNULL, 0);
+ SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
// If we're in the middle of probing this record, we need to start again,
// because changing its rdata may change the outcome of the tie-breaker.
// changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
// so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
- debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating",
+ rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
rr->AnnounceCount = InitialAnnounceCount;
rr->RequireGoodbye = mDNSfalse;
mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
{
- if (!rr->Acknowledged && rr->RecordCallback)
+ if (rr->RecordCallback)
{
// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
rr->Acknowledged = mDNStrue;
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+ mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
rr->RecordCallback(m, rr, mStatus_NoError);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
}
// Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
-#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
-#define RecordIsLocalDuplicate(A,B) ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
+#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
+ ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
+#define RecordIsLocalDuplicate(A,B) \
+ ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
-mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
+// Exported so uDNS.c can call this
+mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
{
domainname *target = GetRRDomainNameTarget(&rr->resrec);
AuthRecord *r;
AuthRecord **p = &m->ResourceRecords;
AuthRecord **d = &m->DuplicateRecords;
- mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
-
if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
{ LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
-
-#ifndef UNICAST_DISABLED
- if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name))
- rr->uDNS_info.id = zeroID;
- else return uDNS_RegisterRecord(m, rr);
-#endif
-
+
+ if (!rr->resrec.RecordType)
+ { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
+
while (*p && *p != rr) p=&(*p)->next;
while (*d && *d != rr) d=&(*d)->next;
if (*d || *p)
{
- LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list",
+ rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
return(mStatus_AlreadyRegistered);
}
rr->next = mDNSNULL;
- // Field Group 1: Persistent metadata for Authoritative Records
-// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
-// rr->Callback = already set in mDNS_SetupResourceRecord
-// rr->Context = already set in mDNS_SetupResourceRecord
-// rr->RecordType = already set in mDNS_SetupResourceRecord
+ // Field Group 1: The actual information pertaining to this resource record
+ // Set up by client prior to call
+
+ // Field Group 2: Persistent metadata for Authoritative Records
+// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
+// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
+// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
+// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client
+// rr->Callback = already set in mDNS_SetupResourceRecord
+// rr->Context = already set in mDNS_SetupResourceRecord
+// rr->RecordType = already set in mDNS_SetupResourceRecord
// rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
// rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client
// Make sure target is not uninitialized data, or we may crash writing debugging log messages
- if (rr->HostTarget && target) target->c[0] = 0;
+ if (rr->AutoTarget && target) target->c[0] = 0;
- // Field Group 2: Transient state for Authoritative Records
+ // Field Group 3: Transient state for Authoritative Records
rr->Acknowledged = mDNSfalse;
rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
rr->AnnounceCount = InitialAnnounceCount;
rr->NR_AnswerTo = mDNSNULL;
rr->NR_AdditionalTo = mDNSNULL;
rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
- if (!rr->HostTarget) InitializeLastAPTime(m, rr);
-// rr->AnnounceUntil = Set for us in InitializeLastAPTime()
+ if (!rr->AutoTarget) InitializeLastAPTime(m, rr);
// rr->LastAPTime = Set for us in InitializeLastAPTime()
// rr->LastMCTime = Set for us in InitializeLastAPTime()
// rr->LastMCInterface = Set for us in InitializeLastAPTime()
rr->NextUpdateCredit = 0;
rr->UpdateBlocked = 0;
+ // Field Group 4: Transient uDNS state for Authoritative Records
+ rr->state = regState_Zero;
+ rr->uselease = 0;
+ rr->expire = 0;
+ rr->Private = 0;
+ rr->id = zeroID;
+ rr->zone.c[0] = 0;
+ rr->UpdateServer = zeroAddr;
+ rr->UpdatePort = zeroIPPort;
+ rr->nta = mDNSNULL;
+ rr->tcp = mDNSNULL;
+ rr->OrigRData = 0;
+ rr->OrigRDLen = 0;
+ rr->InFlightRData = 0;
+ rr->InFlightRDLen = 0;
+ rr->QueuedRData = 0;
+ rr->QueuedRDLen = 0;
+
// rr->resrec.interface = already set in mDNS_SetupResourceRecord
// rr->resrec.name->c = MUST be set by client
// rr->resrec.rrtype = already set in mDNS_SetupResourceRecord
// rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord
// rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
- if (rr->HostTarget)
+ if (rr->AutoTarget)
SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
else
{
for (r = m->ResourceRecords; r; r=r->next)
{
const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
- if (s1 != s2 && SameResourceRecordSignature(&r->resrec, &rr->resrec) && !SameRData(&r->resrec, &rr->resrec))
+ if (s1 != s2 && SameResourceRecordSignature(r, rr) && !SameRData(&r->resrec, &rr->resrec))
break;
}
if (r) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
*p = rr;
}
- // For records that are not going to probe, acknowledge them right away
- if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
- AcknowledgeRecord(m, rr);
-
+ if (rr->resrec.InterfaceID != mDNSInterface_Any || rr->ForceMCast || IsLocalDomain(rr->resrec.name))
+ {
+ // For records that are not going to probe, acknowledge them right away
+ if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+ AcknowledgeRecord(m, rr);
+ }
+#ifndef UNICAST_DISABLED
+ else
+ {
+ if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
+ rr->ProbeCount = 0;
+ rr->AnnounceCount = 0;
+ rr->state = regState_FetchingZoneData;
+ rr->uselease = mDNStrue;
+ rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationCallback, rr);
+ return rr->nta ? mStatus_NoError : mStatus_NoMemoryErr;
+ }
+#endif
+
return(mStatus_NoError);
}
rr->UpdateCallback(m, rr, OldRData); // ... and let the client know
}
-// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
-// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
-// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
-typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
-
// NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
-mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
+// Exported so uDNS.c can call this
+mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
{
AuthRecord *r2;
mDNSu8 RecordType = rr->resrec.RecordType;
AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records
-#ifndef UNICAST_DISABLED
- if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name)))
- return uDNS_DeregisterRecord(m, rr);
-#endif
-
while (*p && *p != rr) p=&(*p)->next;
if (*p)
{
// Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
// deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
- for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
+ for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;
}
else
{
if (*d)
{
AuthRecord *dup = *d;
- debugf("Duplicate record %p taking over from %p %##s (%s)", dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ debugf("Duplicate record %p taking over from %p %##s (%s)",
+ dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
*d = dup->next; // Cut replacement record from DuplicateRecords list
dup->next = rr->next; // And then...
rr->next = dup; // ... splice it in right after the record we're about to delete
dup->v4Requester = rr->v4Requester;
dup->v6Requester = rr->v6Requester;
dup->ThisAPInterval = rr->ThisAPInterval;
- dup->AnnounceUntil = rr->AnnounceUntil;
dup->LastAPTime = rr->LastAPTime;
dup->LastMCTime = rr->LastMCTime;
dup->LastMCInterface = rr->LastMCInterface;
while (*p && *p != rr) p=&(*p)->next;
// If we found our record on the duplicate list, then make sure we don't send a goodbye for it
if (*p) rr->RequireGoodbye = mDNSfalse;
- if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
+ rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
}
if (!*p)
{
// No need to log an error message if we already know this is a potentially repeated deregistration
if (drt != mDNS_Dereg_repeat)
- LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list",
+ rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
return(mStatus_BadReferenceErr);
}
// If this is a shared record and we've announced it at least once,
// we need to retract that announcement before we delete the record
- if (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
+
+ // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local answers then
+ // it's tempting to just do "AnswerLocalQuestions(m, rr, mDNSfalse)" here, but that would not not be safe.
+ // The AnswerLocalQuestions routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
+ // mechanism to cope with the client callback modifying the question list while that's happening.
+ // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
+ // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice.
+ // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other
+ // records, thereby invoking yet more callbacks, without limit.
+ // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending
+ // actual goodbye packets.
+
+#ifndef UNICAST_DISABLED
+ if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly && !rr->ForceMCast && !IsLocalDomain(rr->resrec.name))
+ if (rr->RequireGoodbye)
+ {
+ if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
+ rr->resrec.RecordType = kDNSRecordTypeDeregistering;
+ uDNS_DeregisterRecord(m, rr);
+ // At this point unconditionally we bail out
+ // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
+ // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
+ // process and will complete asynchronously. Either way we don't need to do anything more here.
+ return(mStatus_NoError);
+ }
+#endif UNICAST_DISABLED
+
+ if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->LocalAnswer))
{
- verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr));
rr->resrec.RecordType = kDNSRecordTypeDeregistering;
rr->resrec.rroriginalttl = 0;
rr->ImmedAnswer = mDNSInterfaceMark;
rr->next = mDNSNULL;
if (RecordType == kDNSRecordTypeUnregistered)
- debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered",
- rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
else if (RecordType == kDNSRecordTypeDeregistering)
- debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering",
- rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
else
{
- verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
rr->resrec.RecordType = kDNSRecordTypeUnregistered;
}
// If we have an update queued up which never executed, give the client a chance to free that memory
if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client
-
- if (rr->LocalAnswer) AnswerLocalQuestions(m, rr, mDNSfalse);
+
+ if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
+ if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
// CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
// is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
// In this case the likely client action to the mStatus_MemFree message is to free the memory,
// so any attempt to touch rr after this is likely to lead to a crash.
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+ mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
if (drt != mDNS_Dereg_conflict)
{
- if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
+ if (rr->RecordCallback)
+ rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this
}
else
{
RecordProbeFailure(m, rr);
- if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this
+ if (rr->RecordCallback)
+ rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this
// Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
// Note that with all the client callbacks going on, by the time we get here all the
// records we marked may have been explicitly deregistered by the client anyway.
else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
}
}
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
return(mStatus_NoError);
}
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
-#pragma mark -
#pragma mark - Packet Sending Functions
#endif
if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
AddRecordToResponseList(nrpp, rr->Additional2, rr);
-
+
// For SRV records, automatically add the Address record(s) for the target host
if (rr->resrec.rrtype == kDNSType_SRV)
+ {
for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target
SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
AddRecordToResponseList(nrpp, rr2, rr);
+ }
+ else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional
+ {
+ for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records
+ if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ...
+ ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ...
+ rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name
+ SameDomainName(rr->resrec.name, rr2->resrec.name))
+ AddRecordToResponseList(nrpp, rr2, rr);
+ }
+ else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record
+ {
+ if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) &&
+ SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
+ AddRecordToResponseList(nrpp, &m->DeviceInfo, rr);
+ }
}
}
rr->NR_AdditionalTo = mDNSNULL;
}
- if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, -1, mDNSNULL);
+ if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
}
}
-mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
+mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
{
- // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal()
- // that it should go ahead and immediately dispose of this registration
+ // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
+ // it should go ahead and immediately dispose of this registration
rr->resrec.RecordType = kDNSRecordTypeShared;
rr->RequireGoodbye = mDNSfalse;
+ if (rr->LocalAnswer) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->LocalAnswer = mDNSfalse; }
mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this
}
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNSlocal void DiscardDeregistrations(mDNS *const m)
{
- if (m->CurrentRecord) LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set");
+ if (m->CurrentRecord)
+ LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
m->CurrentRecord = m->ResourceRecords;
while (m->CurrentRecord)
// which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen)
// then all that means is that it won't get sent -- which would not be the end of the world.
for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV)
for (r2=m->ResourceRecords; r2; r2=r2->next) // Scan list of resource records
if (RRTypeIsAddressType(r2->resrec.rrtype) && // For all address records (A/AAAA) ...
SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
(rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
r2->ImmedAdditional = r2->resrec.InterfaceID; // ... then mark this address record for sending too
+ // We also make sure we send the DeviceInfo TXT record too, if necessary
+ // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the
+ // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering).
+ if (rr->ImmedAnswer && rr->resrec.RecordType == kDNSRecordTypeShared && rr->resrec.rrtype == kDNSType_PTR)
+ if (ResourceRecordIsValidAnswer(&m->DeviceInfo) && SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c))
+ {
+ if (!m->DeviceInfo.ImmedAnswer) m->DeviceInfo.ImmedAnswer = rr->ImmedAnswer;
+ else m->DeviceInfo.ImmedAnswer = mDNSInterfaceMark;
+ }
+ }
// If there's a record which is supposed to be unique that we're going to send, then make sure that we give
// the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class
{
for (r2 = m->ResourceRecords; r2; r2=r2->next)
if (ResourceRecordIsValidAnswer(r2))
- if (r2->ImmedAnswer != mDNSInterfaceMark && r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
+ if (r2->ImmedAnswer != mDNSInterfaceMark &&
+ r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr))
r2->ImmedAnswer = rr->ImmedAnswer;
}
else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked
{
for (r2 = m->ResourceRecords; r2; r2=r2->next)
if (ResourceRecordIsValidAnswer(r2))
- if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(&r2->resrec, &rr->resrec))
+ if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr))
r2->ImmedAdditional = rr->ImmedAdditional;
}
}
rr->AnnounceCount--;
rr->ThisAPInterval *= 2;
rr->LastAPTime = m->timenow;
- if (rr->LastAPTime + rr->ThisAPInterval - rr->AnnounceUntil >= 0) rr->AnnounceCount = 0;
debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
}
}
if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
{
newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
- if (!newptr && m->omsg.h.numAnswers) break;
- numDereg++;
- responseptr = newptr;
+ if (newptr) { responseptr = newptr; numDereg++; }
+ else if (m->omsg.h.numAnswers) break;
}
else if (rr->NewRData && !m->SleepState) // If we have new data for this record
{
if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
{
newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
- if (!newptr && m->omsg.h.numAnswers) break;
- numDereg++;
- responseptr = newptr;
- rr->RequireGoodbye = mDNSfalse;
+ if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; }
+ else if (m->omsg.h.numAnswers) break;
}
// Now try to see if we can fit the update in the same packet (not fatal if we can't)
SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl);
rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
- if (!newptr && m->omsg.h.numAnswers) break;
- rr->RequireGoodbye = (mDNSu8) (!m->SleepState);
- if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
- responseptr = newptr;
+ if (newptr)
+ {
+ responseptr = newptr;
+ rr->RequireGoodbye = (mDNSu8) (!m->SleepState);
+ if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
+ }
+ else if (m->omsg.h.numAnswers) break;
}
// If sending on all interfaces, go to next interface; else we're finished now
if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
for (a = m->ResourceRecords; a; a=a->next)
if (a->LastMCTime == m->timenow &&
a->LastMCInterface == intf->InterfaceID &&
- SameResourceRecordSignature(&a->resrec, &rr->resrec)) { SendAdditional = mDNStrue; break; }
+ SameResourceRecordSignature(a, rr)) { SendAdditional = mDNStrue; break; }
}
if (!SendAdditional) // If we don't want to send this after all,
rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field
numAnnounce, numAnnounce == 1 ? "" : "s",
numAnswer, numAnswer == 1 ? "" : "s",
m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
- if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
- if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
+ if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
+ if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
// There might be more things to send on this interface, so go around one more time and try again.
// *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables
// ***
- if (m->CurrentRecord) LogMsg("SendResponses: ERROR m->CurrentRecord already set");
+ if (m->CurrentRecord)
+ LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
m->CurrentRecord = m->ResourceRecords;
while (m->CurrentRecord)
{
{
rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
- verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec",
- rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond);
+ verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks",
+ rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
+ (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
}
if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
m->NextCacheCheck = rr->DelayDelivery;
}
-#define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 15)
-#define kDefaultReconfirmTimeForCableDisconnect ((mDNSu32)mDNSPlatformOneSecond * 5)
-#define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
+#define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
+#define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
+#define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5)
+#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30)
mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
{
if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3))
{
// Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
- interval += mDNSRandom(interval/3);
+ // For all the reconfirmations in a given batch, we want to use the same random value
+ // so that the reconfirmation questions can be grouped into a single query packet
+ if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
+ interval += mDNSRandomFromFixedSeed(m->RandomReconfirmDelay, interval/3);
rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3;
- rr->resrec.rroriginalttl = interval * 4 / mDNSPlatformOneSecond;
+ rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
SetNextCacheCheckTime(m, rr);
}
- debugf("mDNS_Reconfirm_internal:%5ld ticks to go for %s", RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr));
+ debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
+ RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion);
return(mStatus_NoError);
}
mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
if (!newptr)
{
- debugf("BuildQuestion: No more space in this packet for question %##s", q->qname.c);
+ debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
return(mDNSfalse);
}
else if (newptr + *answerforecast >= limit)
{
- verbosedebugf("BuildQuestion: Retracting question %##s new forecast total %d", q->qname.c, newptr + *answerforecast - query->data);
+ verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d",
+ q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data);
query->h.numQuestions--;
return(mDNSfalse);
}
{
mDNSu32 forecast = *answerforecast;
const mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
CacheRecord *rr;
CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update
if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list
rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
- ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
+ SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1)
{
}
}
- // Traffic reduction:
- // If we already have at least one unique answer in the cache,
- // OR we have so many shared answers that the KA list is too big to fit in one packet
- // The we suppress queries number 3 and 5:
- // Query 1 (immediately; ThisQInterval = 1 sec; request unicast replies)
- // Query 2 (after 1 second; ThisQInterval = 2 sec; send normally)
- // Query 3 (after 2 seconds; ThisQInterval = 4 sec; may suppress)
- // Query 4 (after 4 seconds; ThisQInterval = 8 sec; send normally)
- // Query 5 (after 8 seconds; ThisQInterval = 16 sec; may suppress)
- // Query 6 (after 16 seconds; ThisQInterval = 32 sec; send normally)
- if (q->UniqueAnswers || newptr + forecast >= limit)
- if (q->ThisQInterval == InitialQuestionInterval * 8 || q->ThisQInterval == InitialQuestionInterval * 32)
- {
- query->h.numQuestions--;
- ka = *kalistptrptr; // Go back to where we started and retract these answer records
- while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; }
- return(mDNStrue); // Return true: pretend we succeeded, even though we actually suppressed this question
- }
-
// Success! Update our state pointers, increment UnansweredQueries as appropriate, and return
*queryptr = newptr; // Update the packet pointer
*answerforecast = forecast; // Update the forecast
*kalistptrptr = ka; // Update the known answer list pointer
- if (ucast) m->ExpectUnicastResponse = m->timenow;
+ if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow);
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache,
if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list
- ResourceRecordAnswersQuestion(&rr->resrec, q)) // which answers our question
+ SameNameRecordAnswersQuestion(&rr->resrec, q)) // which answers our question
{
rr->UnansweredQueries++; // indicate that we're expecting a response
rr->LastUnansweredTime = m->timenow;
}
}
-mDNSlocal void ReconfirmAntecedents(mDNS *const m, DNSQuestion *q)
+// When we have a query looking for a specified name, but there appear to be no answers with
+// that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process
+// for any records in our cache that reference the given name (e.g. PTR and SRV records).
+// For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name.
+// We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5.
+// A typical reconfirmation scenario might go like this:
+// Depth 0: Name "myhost.local" has no address records
+// Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale
+// Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale
+// Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale
+// Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we
+// found referring to the given name, but not recursively descend any further reconfirm *their* antecedents.
+mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth)
{
mDNSu32 slot;
CacheGroup *cg;
- CacheRecord *rr;
- domainname *target;
- FORALL_CACHERECORDS(slot, cg, rr)
- if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdatahash == q->qnamehash && SameDomainName(target, &q->qname))
- mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
+ CacheRecord *cr;
+ debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c);
+ FORALL_CACHERECORDS(slot, cg, cr)
+ {
+ domainname *crtarget = GetRRDomainNameTarget(&cr->resrec);
+ if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name))
+ {
+ LogOperation("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr));
+ mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+ if (depth < 5) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1);
+ }
+ }
}
// Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
// We forecast: qname (n) type (2) class (2)
mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
const mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
CacheRecord *rr;
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
- ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
+ SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry
rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery
{
mDNSlocal void SendQueries(mDNS *const m)
{
+ mDNSu32 slot;
+ CacheGroup *cg;
+ CacheRecord *cr;
+ AuthRecord *ar;
int pktcount = 0;
DNSQuestion *q;
// For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval
// 1. If time for a query, work out what we need to do
if (m->timenow - m->NextScheduledQuery >= 0)
{
- mDNSu32 slot;
- CacheGroup *cg;
CacheRecord *rr;
- m->NextScheduledQuery = m->timenow + 0x78000000;
// We're expecting to send a query anyway, so see if any expiring cache records are close enough
// to their NextRequiredQuery to be worth batching them together with this one
if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
{
+ LogOperation("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr));
q = rr->CRActiveQuestion;
ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
- if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If unicast query, mark it
+ if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it
+ else if (!mDNSOpaque16IsZero(q->TargetQID)) q->LastQTime = m->timenow - q->ThisQInterval; // For uDNS, adjust LastQTime
else if (q->SendQNow == mDNSNULL) q->SendQNow = rr->resrec.InterfaceID;
else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
}
- // Scan our list of questions to see which *unicast* queries need to be sent
- for (q = m->Questions; q; q=q->next)
- if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
+ if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
+ m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
+
+ // Scan our list of questions to see which:
+ // *WideArea* queries need to be sent
+ // *unicast* queries need to be sent
+ // *multicast* queries we're definitely going to send
+ if (m->CurrentQuestion)
+ LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ m->CurrentQuestion = m->Questions;
+ while (m->CurrentQuestion)
+ {
+ q = m->CurrentQuestion;
+ if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m);
+ else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
{
mDNSu8 *qptr = m->omsg.data;
const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
- mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, -1, mDNSNULL);
- q->ThisQInterval *= 2;
+ mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
+ q->ThisQInterval *= QuestionIntervalStep;
if (q->ThisQInterval > MaxQuestionInterval)
q->ThisQInterval = MaxQuestionInterval;
- q->LastQTime = m->timenow;
- q->LastQTxTime = m->timenow;
- q->RecentAnswerPkts = 0;
- q->SendQNow = mDNSNULL;
- m->ExpectUnicastResponse = m->timenow;
+ q->LastQTime = m->timenow;
+ q->LastQTxTime = m->timenow;
+ q->RecentAnswerPkts = 0;
+ q->SendQNow = mDNSNULL;
+ q->ExpectUnicastResp = NonZeroTime(m->timenow);
}
-
- // Scan our list of questions to see which *multicast* queries we're definitely going to send
- for (q = m->Questions; q; q=q->next)
- if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+ else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
{
+ //LogOperation("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
if (maxExistingQuestionInterval < q->ThisQInterval)
maxExistingQuestionInterval = q->ThisQInterval;
}
-
+ // If m->CurrentQuestion wasn't modified out from under us, advance it now
+ // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
+ // m->CurrentQuestion point to the right question
+ if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
+ }
+
// Scan our list of questions
// (a) to see if there are any more that are worth accelerating, and
// (b) to update the state variables for *all* the questions we're going to send
+ // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
+ // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
+ // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
+ m->NextScheduledQuery = m->timenow + 0x78000000;
for (q = m->Questions; q; q=q->next)
{
- if (q->SendQNow ||
- (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))
+ if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
+ (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
{
// If at least halfway to next query time, advance to next interval
- // If less than halfway to next query time, treat this as logically a repeat of the last transmission, without advancing the interval
+ // If less than halfway to next query time, then
+ // treat this as logically a repeat of the last transmission, without advancing the interval
if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
{
+ //LogOperation("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
- q->ThisQInterval *= 2;
+ q->ThisQInterval *= QuestionIntervalStep;
if (q->ThisQInterval > MaxQuestionInterval)
q->ThisQInterval = MaxQuestionInterval;
- else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * 8)
+ else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep2)
{
- debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents", q->qname.c, DNSTypeName(q->qtype));
- ReconfirmAntecedents(m, q); // If sending third query, and no answers yet, time to begin doubting the source
+ // Generally don't need to log this.
+ // It's not especially noteworthy if a query finds no results -- this usually happens for domain
+ // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
+ // and when there simply happen to be no instances of the service the client is looking
+ // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
+ debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
+ q->qname.c, DNSTypeName(q->qtype));
+ // Sending third query, and no answers yet; time to begin doubting the source
+ ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
}
}
{
m->NextScheduledProbe = m->timenow + 0x78000000;
- if (m->CurrentRecord) LogMsg("SendQueries: ERROR m->CurrentRecord already set");
+ if (m->CurrentRecord)
+ LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
m->CurrentRecord = m->ResourceRecords;
while (m->CurrentRecord)
{
rr->LastAPTime = m->timenow;
rr->ProbeCount--;
SetNextAnnounceProbeTime(m, rr);
+ if (rr->ProbeCount == 0)
+ {
+ // If this is the last probe for this record, then see if we have any matching records
+ // on our duplicate list which should similarly have their ProbeCount cleared to zero...
+ AuthRecord *r2;
+ for (r2 = m->DuplicateRecords; r2; r2=r2->next)
+ if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
+ r2->ProbeCount = 0;
+ // ... then acknowledge this record to the client.
+ // We do this optimistically, just as we're about to send the third probe.
+ // This helps clients that both advertise and browse, and want to filter themselves
+ // from the browse results list, because it helps ensure that the registration
+ // confirmation will be delivered 1/4 second *before* the browse "add" event.
+ // A potential downside is that we could deliver a registration confirmation and then find out
+ // moments later that there's a name conflict, but applications have to be prepared to handle
+ // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
+ if (!rr->Acknowledged) AcknowledgeRecord(m, rr);
+ }
}
- // else, if it has now finished probing, move it to state Verified, and update m->NextScheduledResponse so it will be announced
+ // else, if it has now finished probing, move it to state Verified,
+ // and update m->NextScheduledResponse so it will be announced
else
{
- AuthRecord *r2;
+ if (!rr->Acknowledged) AcknowledgeRecord(m, rr); // Defensive, just in case it got missed somehow
rr->resrec.RecordType = kDNSRecordTypeVerified;
rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
rr->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique;
SetNextAnnounceProbeTime(m, rr);
- // If we have any records on our duplicate list that match this one, they have now also completed probing
- for (r2 = m->DuplicateRecords; r2; r2=r2->next)
- if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
- r2->ProbeCount = 0;
- AcknowledgeRecord(m, rr);
}
}
}
{
AuthRecord *rr = m->CurrentRecord;
m->CurrentRecord = rr->next;
- if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0)
+ if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged)
AcknowledgeRecord(m, rr);
}
}
- // 3. Now we know which queries and probes we're sending, go through our interface list sending the appropriate queries on each interface
+ // 3. Now we know which queries and probes we're sending,
+ // go through our interface list sending the appropriate queries on each interface
while (intf)
{
AuthRecord *rr;
// Put query questions in this packet
for (q = m->Questions; q; q=q->next)
- if (q->SendQNow == intf->InterfaceID)
+ {
+ if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow == intf->InterfaceID))
{
debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d",
SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ",
BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
}
+ }
// Put probe questions in this packet
for (rr = m->ResourceRecords; rr; rr=rr->next)
answerforecast = forecast;
rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
rr->IncludeInProbe = mDNStrue;
- verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
+ verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d",
+ rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
}
else
{
- verbosedebugf("SendQueries: Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ verbosedebugf("SendQueries: Retracting Question %##s (%s)",
+ rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
m->omsg.h.numQuestions--;
}
}
mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
if (newptr)
{
- verbosedebugf("SendQueries: Put %##s (%s) at %d - %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
+ verbosedebugf("SendQueries: Put %##s (%s) at %d - %d",
+ rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
queryptr = newptr;
KnownAnswerList = rr->NextInKAList;
rr->NextInKAList = mDNSNULL;
m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
- if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL);
- if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL);
+ if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL);
+ if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL);
if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
if (++pktcount >= 1000)
{ LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
}
}
- // Final sanity check for debugging purposes
- {
- AuthRecord *rr;
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->SendRNow)
- {
- if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
- LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, rr));
- rr->SendRNow = mDNSNULL;
- }
- }
+ // 4. Final housekeeping
+
+ // 4a. Debugging check: Make sure we announced all our records
+ for (ar = m->ResourceRecords; ar; ar=ar->next)
+ if (ar->SendRNow)
+ {
+ if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
+ LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
+ ar->SendRNow = mDNSNULL;
+ }
+
+ // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope
+ // that their interface which went away might come back again, the logic will want to send queries
+ // for those records, but we can't because their interface isn't here any more, so to keep the
+ // state machine ticking over we just pretend we did so.
+ // If the interface does not come back in time, the cache record will expire naturally
+ FORALL_CACHERECORDS(slot, cg, cr)
+ if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
+ {
+ cr->UnansweredQueries++;
+ cr->CRActiveQuestion->SendQNow = mDNSNULL;
+ SetNextCacheCheckTime(m, cr);
+ }
+
+ // 4c. Debugging check: Make sure we sent all our planned questions
+ // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
+ // we legitimately couldn't send because the interface is no longer available
+ for (q = m->Questions; q; q=q->next)
+ if (q->SendQNow)
+ {
+ LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->SendQNow = mDNSNULL;
+ }
}
// ***************************************************************************
#pragma mark - RR List Management & Task Management
#endif
-// NOTE: AnswerQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
-// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
-mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, CacheRecord *rr, mDNSBool AddRecord)
+// NOTE: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
+// Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
+// In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
+// which will be auto-advanced (possibly to NULL) if the client callback cancels the question.
+mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord)
{
- verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)",
- q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ DNSQuestion *const q = m->CurrentQuestion;
+ mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord &&
+ rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME;
+ verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
- // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue)
+ // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
// may be called twice, once when the record is received, and again when it's time to notify local clients.
// If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this.
rr->LastUsed = m->timenow;
- if (ActiveQuestion(q) && rr->CRActiveQuestion != q)
+ if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q)
{
if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
+ debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
rr->CRActiveQuestion = q; // We know q is non-null
SetNextCacheCheckTime(m, rr);
}
// (b) a normal add, where we have at least one unique-type answer,
// then there's no need to keep polling the network.
// (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
- if ((AddRecord == 2 && !q->RequestUnicast) ||
- (AddRecord == 1 && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
- if (ActiveQuestion(q))
+ // We do this for mDNS questions and uDNS one-shot questions, but not for
+ // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing.
+ if ((AddRecord == QC_addnocache && !q->RequestUnicast) ||
+ (AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
+ if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived))
{
- q->LastQTime = m->timenow;
- q->LastQTxTime = m->timenow;
+ q->LastQTime = m->timenow;
+ q->LastQTxTime = m->timenow;
q->RecentAnswerPkts = 0;
- q->ThisQInterval = MaxQuestionInterval;
- q->RequestUnicast = mDNSfalse;
+ q->ThisQInterval = MaxQuestionInterval;
+ q->RequestUnicast = mDNSfalse;
}
if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- if (q->QuestionCallback)
+ // Only deliver negative answers if client has explicitly requested them
+ if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && (!AddRecord || !q->ReturnIntermed)) return;
+
+ // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that
+ if (q->QuestionCallback && !q->NoAnswer && (!followcname || q->ReturnIntermed))
+ {
+ mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
q->QuestionCallback(m, q, &rr->resrec, AddRecord);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- // CAUTION: MUST NOT do anything more with q after calling q->QuestionCallback(), because the client's callback function
- // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
- // Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv()
- // and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions
- // being deleted out from under them.
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
+ }
+ // NOTE: Proceed with caution here because client callback function is allowed to do anything,
+ // including starting/stopping queries, registering/deregistering records, etc.
+
+ if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10)
+ {
+ const mDNSu32 c = q->CNAMEReferrals + 1;
+ // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
+ // and track CNAMEs coming and going, we should really create a subbordinate query here,
+ // which we would subsequently cancel and retract if the CNAME referral record were removed.
+ // In reality this is such a corner case we'll ignore it until someone actually needs it.
+ LogOperation("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr));
+ mDNS_StopQuery_internal(m, q); // Stop old query
+ AssignDomainName(&q->qname, &rr->resrec.rdata->u.name); // Update qname
+ q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
+ mDNS_StartQuery_internal(m, q); // start new query
+ q->CNAMEReferrals = c; // and keep count of how many times we've done this
+ }
}
mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
{
rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
- if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set");
+ if (m->CurrentQuestion)
+ LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
DNSQuestion *q = m->CurrentQuestion;
- m->CurrentQuestion = q->next;
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
+ AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
+ m->CurrentQuestion = q->next;
}
m->CurrentQuestion = mDNSNULL;
}
CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
CacheRecord *rr;
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (rr->resrec.namehash == namehash && SameDomainName(rr->resrec.name, name))
- if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second
- if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted
- delay = RRExpireTime(rr);
+ if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second
+ if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted
+ delay = RRExpireTime(rr);
if (delay - start > 0) return(NonZeroTime(delay));
else return(0);
}
// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
// rr is a new CacheRecord just received into our cache
// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
-// NOTE: CacheRecordAdd calls AnswerQuestionWithResourceRecord which can call a user callback,
+// NOTE: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
// which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
{
- if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set");
- m->CurrentQuestion = m->Questions;
- while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+ DNSQuestion *q;
+ for (q = m->Questions; q; q=q->next)
{
- DNSQuestion *q = m->CurrentQuestion;
- m->CurrentQuestion = q->next;
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
{
- // If this question is one that's actively sending queries, and it's received ten answers within one second of sending the last
- // query packet, then that indicates some radical network topology change, so reset its exponential backoff back to the start.
- // We must be at least at the eight-second interval to do this. If we're at the four-second interval, or less,
- // there's not much benefit accelerating because we will anyway send another query within a few seconds.
- // The first reset query is sent out randomized over the next four seconds to reduce possible synchronization between machines.
+ // If this question is one that's actively sending queries, and it's received ten answers within one
+ // second of sending the last query packet, then that indicates some radical network topology change,
+ // so reset its exponential backoff back to the start. We must be at least at the eight-second interval
+ // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating
+ // because we will anyway send another query within a few seconds. The first reset query is sent out
+ // randomized over the next four seconds to reduce possible synchronization between machines.
if (q->LastAnswerPktNum != m->PktNum)
{
q->LastAnswerPktNum = m->PktNum;
- if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
- q->ThisQInterval > InitialQuestionInterval*32 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
+ if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
+ q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
{
LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
q->qname.c, DNSTypeName(q->qtype));
SetNextQueryTime(m,q);
}
}
- verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
+ verbosedebugf("CacheRecordAdd %p %##s (%s) %lu",
+ rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
q->CurrentAnswers++;
if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
if (msgcount++ < 10)
LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
- rr->resrec.rroriginalttl = 1;
+ rr->resrec.rroriginalttl = 0;
rr->UnansweredQueries = MaxUnansweredQueries;
}
- AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
- // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
}
}
- m->CurrentQuestion = mDNSNULL;
+
+ if (!rr->DelayDelivery)
+ {
+ if (m->CurrentQuestion)
+ LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ m->CurrentQuestion = m->Questions;
+ while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+ {
+ DNSQuestion *q = m->CurrentQuestion;
+ if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
+ m->CurrentQuestion = q->next;
+ }
+ m->CurrentQuestion = mDNSNULL;
+ }
+
SetNextCacheCheckTime(m, rr);
}
// but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
// way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
// so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
-// NOTE: NoCacheAnswer calls AnswerQuestionWithResourceRecord which can call a user callback,
+// NOTE: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
// which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
{
LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
- if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set");
+ if (m->CurrentQuestion)
+ LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion)
{
DNSQuestion *q = m->CurrentQuestion;
- m->CurrentQuestion = q->next;
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- AnswerQuestionWithResourceRecord(m, q, rr, 2); // Value '2' indicates "don't expect 'remove' events for this"
- // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
+ AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this"
+ if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
+ m->CurrentQuestion = q->next;
}
m->CurrentQuestion = mDNSNULL;
}
// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
// rr is an existing cache CacheRecord that just expired and is being deleted
// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
-// NOTE: CacheRecordRmv calls AnswerQuestionWithResourceRecord which can call a user callback,
+// NOTE: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
// which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
{
- if (m->CurrentQuestion) LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set");
+ if (m->CurrentQuestion)
+ LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
DNSQuestion *q = m->CurrentQuestion;
- m->CurrentQuestion = q->next;
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
{
verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
+ q->FlappingInterface1 = mDNSNULL;
+ q->FlappingInterface2 = mDNSNULL;
if (q->CurrentAnswers == 0)
- LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", q, q->qname.c, DNSTypeName(q->qtype));
+ LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
+ q, q->qname.c, DNSTypeName(q->qtype));
else
{
q->CurrentAnswers--;
if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
}
- if (q->CurrentAnswers == 0)
+ if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
{
- debugf("CacheRecordRmv: Zero current answers for %##s (%s); will reconfirm antecedents", q->qname.c, DNSTypeName(q->qtype));
- ReconfirmAntecedents(m, q);
+ if (q->CurrentAnswers == 0)
+ {
+ LogOperation("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
+ q->qname.c, DNSTypeName(q->qtype));
+ ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
+ }
+ AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
}
- AnswerQuestionWithResourceRecord(m, q, rr, mDNSfalse);
- // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
}
+ if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
+ m->CurrentQuestion = q->next;
}
m->CurrentQuestion = mDNSNULL;
}
mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
{
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
unsigned int i;
for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
#endif
mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
{
CacheEntity *e = (CacheEntity *)(*cp);
- //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
- if ((*cp)->rrcache_tail != &(*cp)->members) LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
- //if ((*cp)->name != (domainname*)((*cp)->namestorage)) LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
+ //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
+ if ((*cp)->rrcache_tail != &(*cp)->members)
+ LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
+ //if ((*cp)->name != (domainname*)((*cp)->namestorage))
+ // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
(*cp)->name = mDNSNULL;
*cp = (*cp)->next; // Cut record from list
mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
{
+ //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
r->resrec.rdata = mDNSNULL;
ReleaseCacheEntity(m, (CacheEntity *)r);
}
-// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering CacheRecordDeferredAdd calls
-// The in-order nature of the cache lists ensures that all callbacks for old records are delivered before callbacks for newer records
-mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg)
+// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering
+// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all
+// callbacks for old records are delivered before callbacks for newer records.
+mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
{
CacheRecord **rp = &cg->members;
if (m->timenow - event >= 0) // If expired, delete it
{
*rp = rr->next; // Cut it from the list
- verbosedebugf("CheckCacheExpiration: Deleting %s", CRDisplayString(m, rr));
+ verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s",
+ m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away
{
CacheRecordRmv(m, rr);
// SendQueries() will see that we have records close to expiration, and send FEQs for them.
m->NextScheduledQuery = m->timenow;
// After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
- // which will correctly update m->NextCacheCheck for us
+ // which will correctly update m->NextCacheCheck for us.
event = m->timenow + 0x3FFFFFFF;
}
}
}
+ verbosedebugf("CheckCacheExpiration:%6d %5d %s",
+ (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
rp = &rr->next;
CacheRecord *rr;
DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer
const mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
// This should be safe, because calling the client's question callback may cause the
// question list to be modified, but should not ever cause the rrcache list to be modified.
- // If the client's question callback deletes the question, then m->CurrentQuestion will
+ // If the client's question callback deletes the question, then m->CurrentQuestion will
// be advanced, and we'll exit out of the loop
m->lock_rrcache = 1;
- if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set");
+ if (m->CurrentQuestion)
+ LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
- if (q->InterfaceID == mDNSInterface_Any) // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
+ if (q->NoAnswer == NoAnswer_Fail)
+ {
+ LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60);
+ q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression
+ AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
+ q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ }
+
+ // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
+ if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any)
{
- if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
+ if (m->CurrentRecord)
+ LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
m->CurrentRecord = m->ResourceRecords;
while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
{
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
{
AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
- // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
- m->CurrentRecord = mDNSNULL;
+ m->CurrentRecord = mDNSNULL;
}
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- {
- // SecsSinceRcvd is whole number of elapsed seconds, rounded down
- mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
- if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
+ if (m->CurrentQuestion == q)
+ {
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ if (SameNameRecordAnswersQuestion(&rr->resrec, q))
{
- LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s)",
- rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
- continue; // Go to next one in loop
+ // SecsSinceRcvd is whole number of elapsed seconds, rounded down
+ mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
+ if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
+ {
+ LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s) %d %d",
+ rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), m->timenow, rr->TimeRcvd);
+ continue; // Go to next one in loop
+ }
+
+ // If this record set is marked unique, then that means we can reasonably assume we have the whole set
+ // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
+ if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
+ ShouldQueryImmediately = mDNSfalse;
+ q->CurrentAnswers++;
+ if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+ if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+ AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
+ else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
+ if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
+ ShouldQueryImmediately = mDNSfalse;
+ }
- // If this record set is marked unique, then that means we can reasonably assume we have the whole set
- // -- we don't need to rush out on the network and query immediately to see if there are more answers out there
- if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
- ShouldQueryImmediately = mDNSfalse;
- q->CurrentAnswers++;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
- AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue);
- // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
- if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
- }
- else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
- if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
- ShouldQueryImmediately = mDNSfalse;
-
- if (ShouldQueryImmediately && m->CurrentQuestion == q)
+ if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q))
{
q->ThisQInterval = InitialQuestionInterval;
q->LastQTime = m->timenow - q->ThisQInterval;
+ if (mDNSOpaque16IsZero(q->TargetQID))
+ {
+ // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms
+ if (!m->RandomQueryDelay)
+ m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1;
+ q->LastQTime += m->RandomQueryDelay;
+ }
+
m->NextScheduledQuery = m->timenow;
}
+
m->CurrentQuestion = mDNSNULL;
m->lock_rrcache = 0;
}
-// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any appropriate answers,
-// stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
+// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any
+// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
{
DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer
debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- if (m->CurrentQuestion) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set");
+ if (m->CurrentQuestion)
+ LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
- if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
+ if (m->CurrentRecord)
+ LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
m->CurrentRecord = m->ResourceRecords;
+
while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
{
AuthRecord *rr = m->CurrentRecord;
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
{
AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
- // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
// We don't want to be vulnerable to a malicious attacker flooding us with an infinite
// number of bogus records so that we keep growing our cache until the machine runs out of memory.
- // To guard against this, if we're actively using less than 1/32 of our cache, then we
- // purge all the unused records and recycle them, instead of allocating more memory.
- if (m->rrcache_size >= 512 && m->rrcache_size / 32 > m->rrcache_active)
- debugf("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
+ // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each),
+ // and we're actively using less than 1/32 of that cache, then we purge all the unused records
+ // and recycle them, instead of allocating more memory.
+ if (m->rrcache_size > 3000 && m->rrcache_size / 32 > m->rrcache_active)
+ LogOperation("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
m->rrcache_size, m->rrcache_active);
else
{
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+ mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
m->MainCallback(m, mStatus_GrowCache);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
}
// Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass.
if (!m->rrcache_free)
{
- #if MDNS_DEBUGMSGS
+ #if LogAllOperations || MDNS_DEBUGMSGS
mDNSu32 oldtotalused = m->rrcache_totalused;
#endif
mDNSu32 slot;
ReleaseCacheRecord(m, rr);
}
}
- if ((*cp)->rrcache_tail != rp) verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
+ if ((*cp)->rrcache_tail != rp)
+ verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
(*cp)->rrcache_tail = rp;
if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
else ReleaseCacheGroup(m, cp);
}
}
- #if MDNS_DEBUGMSGS
- debugf("Clear unused records; m->rrcache_totalused was %lu; now %lu", oldtotalused, m->rrcache_totalused);
- #endif
+ LogOperation("GetCacheEntity recycled %d records to reduce cache from %d to %d",
+ oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
}
if (m->rrcache_free) // If there are records in the free list, take one
m->rrcache_free = e->next;
if (++m->rrcache_totalused >= m->rrcache_report)
{
- debugf("RR Cache now using %ld objects", m->rrcache_totalused);
+ LogOperation("RR Cache now using %ld objects", m->rrcache_totalused);
if (m->rrcache_report < 100) m->rrcache_report += 10;
else m->rrcache_report += 100;
}
cg->members = mDNSNULL;
cg->rrcache_tail = &cg->members;
cg->name = (domainname*)cg->namestorage;
- //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
+ //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s",
+ // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
if (!cg->name)
{
return(cg);
}
-mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
+mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
{
// Make sure we mark this record as thoroughly expired -- we don't ever want to give
// a positive answer using an expired record (e.g. from an interface that has gone away).
int i;
verbosedebugf("mDNS_Execute");
- if (m->CurrentQuestion) LogMsg("mDNS_Execute: ERROR! m->CurrentQuestion already set");
+ if (m->CurrentQuestion)
+ LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
// 1. If we're past the probe suppression time, we can clear it
if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
{
// If the platform code is ready, and we're not suppressing packet generation right now
// then send our responses, probes, and questions.
- // We check the cache first, because there might be records close to expiring that trigger questions to refresh them
+ // We check the cache first, because there might be records close to expiring that trigger questions to refresh them.
// We send queries next, because there might be final-stage probes that complete their probing here, causing
// them to advance to announcing state, and we want those to be included in any announcements we send out.
- // Finally, we send responses, including the previously mentioned records that just completed probing
+ // Finally, we send responses, including the previously mentioned records that just completed probing.
m->SuppressSending = 0;
// 6. Send Query packets. This may cause some probing records to advance to announcing state
if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
if (m->timenow - m->NextScheduledQuery >= 0)
{
- LogMsg("mDNS_Execute: SendQueries didn't send all its queries; will try again in one second");
+ DNSQuestion *q;
+ LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second",
+ m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery);
m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
+ for (q = m->Questions; q; q=q->next)
+ if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0)
+ LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
}
if (m->timenow - m->NextScheduledProbe >= 0)
{
- LogMsg("mDNS_Execute: SendQueries didn't send all its probes; will try again in one second");
+ LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second",
+ m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe);
m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
}
}
}
- m->RandomQueryDelay = 0; // Clear m->RandomQueryDelay, ready to pick a new different value, when necessary
+ // Clear RandomDelay values, ready to pick a new different value next time
+ m->RandomQueryDelay = 0;
+ m->RandomReconfirmDelay = 0;
}
// Note about multi-threaded systems:
{
#ifndef UNICAST_DISABLED
uDNS_Sleep(m);
-#endif
+#endif
// Mark all the records we need to deregister and send them
for (rr = m->ResourceRecords; rr; rr=rr->next)
if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
#endif
// 1. Retrigger all our questions
for (q = m->Questions; q; q=q->next) // Scan our list of questions
- if (ActiveQuestion(q))
+ if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
{
q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
// 2. Re-validate our cache records
m->NextCacheCheck = m->timenow;
FORALL_CACHERECORDS(slot, cg, cr)
- mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForCableDisconnect);
+ mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
// 3. Retrigger probing and announcing for all our authoritative records
for (rr = m->ResourceRecords; rr; rr=rr->next)
if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype;
if (!result) result = CompareRData(our, &m->rec.r);
if (result > 0)
- debugf("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+ LogOperation("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
else if (result < 0)
{
- debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+ LogOperation("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
goto exit;
}
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
}
if (!FoundUpdate)
- debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+ LogOperation("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
exit:
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
}
CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
CacheRecord *rr;
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalResourceRecord(pktrr, &rr->resrec)) break;
+ if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
return(rr);
}
// ProcessQuery examines a received query to see if we have any answers to give
mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end,
- const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast, mDNSBool QueryWasLocalUnicast,
- DNSMessage *const response)
+ const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
+ mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
{
- mDNSBool FromLocalSubnet = AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ mDNSBool FromLocalSubnet = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
AuthRecord *ResponseRecords = mDNSNULL;
AuthRecord **nrp = &ResponseRecords;
CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated
// Also note: we just mark potential answer records here, without trying to build the
// "ResponseRecords" list, because we don't want to risk user callbacks deleting records
// from that list while we're in the middle of trying to build it.
- if (m->CurrentRecord) LogMsg("ProcessQuery ERROR m->CurrentRecord already set");
+ if (m->CurrentRecord)
+ LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
m->CurrentRecord = m->ResourceRecords;
while (m->CurrentRecord)
{
// Make a list indicating which of our own cache records we expect to see updated as a result of this query
// Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
+ if (SameNameRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
if (!rr->NextInKAList && eap != &rr->NextInKAList)
{
*eap = rr;
if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
if (!q->InterfaceID || q->InterfaceID == InterfaceID)
if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
- if (q->qtype == pktq.qtype && q->qclass == pktq.qclass && q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
+ if (q->qtype == pktq.qtype &&
+ q->qclass == pktq.qclass &&
+ q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
{ *dqp = q; dqp = &q->NextInDQList; }
}
}
const mDNSInterfaceID InterfaceID)
{
mDNSu8 *responseend = mDNSNULL;
- mDNSBool QueryWasLocalUnicast = !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr &&
+ !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
- if (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr))
+ if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr))
{
- LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
+ LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
return;
}
-
- verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+
+ verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
- (srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
+ !mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
if (responseend) // If responseend is non-null, that means we built a unicast response packet
{
m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
- mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, -1, mDNSNULL);
+ mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, mDNSNULL, mDNSNULL);
+ }
+ }
+
+mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr)
+ {
+ DNSServer *s;
+ (void)m; // Unused
+ (void)srcaddr; // Unused
+ for (s = m->DNSServers; s; s = s->next)
+ if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue);
+ return(mDNSfalse);
+ }
+
+mDNSlocal const DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSOpaque16 id, const DNSQuestion *const question)
+ {
+ DNSQuestion *q;
+ for (q = m->Questions; q; q=q->next)
+ if (mDNSSameOpaque16(q->TargetQID, id) &&
+ q->qtype == question->qtype &&
+ q->qclass == question->qclass &&
+ q->qnamehash == question->qnamehash &&
+ SameDomainName(&q->qname, &question->qname))
+ return(q);
+ return(mDNSNULL);
+ }
+
+mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSOpaque16 id, const CacheRecord *const rr)
+ {
+ DNSQuestion *q;
+ (void)id;
+ for (q = m->Questions; q; q=q->next)
+ if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ {
+ if (!mDNSOpaque16IsZero(q->TargetQID))
+ {
+ // For now we don't do this check -- for LLQ updates, the ID doesn't seem to match the ID in the question
+ // if (mDNSSameOpaque16(q->TargetQID, id)
+ {
+ if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
+ if (mDNSSameOpaque16(q->TargetQID, id)) return(mDNStrue);
+ // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
+ if (TrustedSource(m, srcaddr)) return(mDNStrue);
+ LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) %#a from %#a: %s",
+ q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr));
+ return(mDNSfalse);
+ }
+ }
+ else
+ {
+ if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2))
+ return(mDNStrue);
+ }
+ }
+ return(mDNSfalse);
+ }
+
+mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg)
+ {
+ CacheRecord *rr = mDNSNULL;
+
+ // Certain data types need more space for in-memory storage than their in-packet rdlength would imply
+ // Currently this applies only to rdata types containing more than one domainname,
+ // or types where the domainname is not the last item in the structure
+ mDNSu16 RDLength;
+ switch (m->rec.r.resrec.rrtype)
+ {
+ case kDNSType_SOA: RDLength = sizeof(rdataSOA); break;
+ case kDNSType_RP: RDLength = sizeof(rdataRP); break;
+ case kDNSType_PX: RDLength = sizeof(rdataPX); break;
+ default: RDLength = m->rec.r.resrec.rdlength; break;
+ }
+
+ //if (RDLength > InlineCacheRDSize)
+ // LogOperation("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r));
+
+ if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); // If we don't have a CacheGroup for this name, make one now
+ if (cg) rr = GetCacheRecord(m, cg, RDLength); // Make a cache record, being careful not to recycle cg
+ if (!rr) NoCacheAnswer(m, &m->rec.r);
+ else
+ {
+ RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer
+ *rr = m->rec.r; // Block copy the CacheRecord object
+ rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
+ rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
+
+ // If this is an oversized record with external storage allocated, copy rdata to external storage
+ if (rr->resrec.rdata == (RData*)&rr->rdatastorage && RDLength > InlineCacheRDSize)
+ LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
+ else if (rr->resrec.rdata != (RData*)&rr->rdatastorage && RDLength <= InlineCacheRDSize)
+ LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
+ if (RDLength > InlineCacheRDSize)
+ mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength);
+
+ rr->next = mDNSNULL; // Clear 'next' pointer
+ *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list
+ cg->rrcache_tail = &(rr->next); // Advance tail pointer
+ if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+ rr->DelayDelivery = NonZeroTime(m->timenow);
+ else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask && // If marked unique,
+ rr->resrec.rdata->MaxRDLength != 0) // and non-negative, assume we may have
+ rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond); // to delay delivery of this 'add' event
+ else
+ rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
+
+ CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
+ }
+ return(rr);
+ }
+
+mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
+ {
+ rr->TimeRcvd = m->timenow;
+ rr->resrec.rroriginalttl = ttl;
+ rr->UnansweredQueries = 0;
+ rr->MPUnansweredQ = 0;
+ rr->MPUnansweredKA = 0;
+ rr->MPExpectingKA = mDNSfalse;
+ SetNextCacheCheckTime(m, rr);
+ }
+
+mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease)
+ {
+ CacheRecord *rr;
+ const mDNSu32 slot = HashSlot(&q->qname);
+ CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ if (rr->CRActiveQuestion == q)
+ {
+ //LogOperation("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr));
+ RefreshCacheRecord(m, rr, lease);
+ }
+ }
+
+mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // TTL in seconds
+ {
+ if (LLQType == uDNS_LLQ_Poll) ttl = LLQ_POLL_INTERVAL * 2 / mDNSPlatformOneSecond;
+ else if (LLQType == uDNS_LLQ_Setup) ttl = kLLQ_DefLease;
+ else if (LLQType == uDNS_LLQ_Events)
+ {
+ // If the TTL is -1 for uDNS LLQ event packet, that means "remove"
+ if (ttl == 0xFFFFFFFF) ttl = 0;
+ else ttl = kLLQ_DefLease;
+ }
+ else // else not LLQ (standard uDNS response)
+ {
+ // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we
+ // also do this check here to make sure we can't get integer overflow below
+ if (ttl > 0x8000000UL) ttl = 0x8000000UL;
+
+ // Adjustment factor to avoid race condition:
+ // Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100.
+ // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
+ // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
+ // To avoid this, we extend the record's effective TTL to give it a little extra grace period.
+ // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds,
+ // the cached copy at our local caching server will already have expired, so the server will be forced
+ // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
+ ttl += ttl/4 + 2;
+
+ // For mDNS, TTL zero means "delete this record"
+ // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
+ // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
+ // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
+ // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
+ if (ttl < 15) ttl = 15;
}
+
+ return ttl;
}
// NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
const mDNSInterfaceID InterfaceID)
{
int i;
-
- // We ignore questions (if any) in a DNS response packet
- const mDNSu8 *ptr = LocateAnswers(response, end);
+ mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
+ mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport);
// "(CacheRecord*)1" is a special (non-zero) end-of-list marker
// We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
// to guard against spoof responses, then the only credible protection against that is cryptographic
// security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record
int totalrecords = response->h.numAnswers + response->h.numAuthorities + response->h.numAdditionals;
+ const mDNSu8 *ptr = response->data;
- (void)srcaddr; // Currently used only for display in debugging message
+ // Currently used only for display in debugging message
(void)srcport;
(void)dstport;
- verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+ debugf("Received Response from %#-15a addressed to %#-15a on %p with "
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
srcaddr, dstaddr, InterfaceID,
response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,",
response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
- response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
-
- // If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us
- if (!mDNSAddrIsDNSMulticast(dstaddr))
+ response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType);
+
+ // 1. We ignore questions (if any) in mDNS response packets
+ // 2. If this is an LLQ response, we handle it much the same
+ // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this
+ // answer as being the authoritative complete RRSet, and respond by deleting all other
+ // matching cache records that don't appear in this packet.
+ // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged
+ if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC))
+ ptr = LocateAnswers(response, end);
+ // Otherwise, for one-shot queries, any answers in our cache that are not also contained
+ // in this response packet are immediately deemed to be invalid.
+ else
{
- if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2))
- return;
- // For now we don't put standard wide-area unicast responses in our main cache
- // (Later we should fix this and cache all known results in a unified manner.)
- if (response->h.id.NotAnInteger != 0 || srcport.NotAnInteger != MulticastDNSPort.NotAnInteger)
- return;
+ // We could possibly combine this with the similar loop at the end of this function --
+ // instead of tagging cache records here and then rescuing them if we find them in the answer section,
+ // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
+ // which it was received (or refreshed), and then at the end if we find any cache records which
+ // answer questions in this packet's question section, but which aren't tagged with this packet's
+ // packet number, then we deduce they are old and delete them
+ for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
+ {
+ DNSQuestion q;
+ ptr = getQuestion(response, ptr, end, InterfaceID, &q);
+ if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q))
+ {
+ CacheRecord *rr;
+ const mDNSu32 slot = HashSlot(&q.qname);
+ CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ if (SameNameRecordAnswersQuestion(&rr->resrec, &q))
+ {
+ //LogMsg("uDNS Q for %s", CRDisplayString(m, rr));
+ // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
+ rr->TimeRcvd = m->timenow - rr->resrec.rroriginalttl * mDNSPlatformOneSecond;
+ rr->UnansweredQueries = MaxUnansweredQueries;
+ }
+ }
+ }
}
for (i = 0; i < totalrecords && ptr && ptr < end; i++)
{
+ // All responses sent via LL multicast are acceptable for caching
+ // All responses received over our outbound TCP connections are acceptable for caching
+ mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType;
+ // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
+ // to any specific question -- any code reading records from the cache needs to make that determination for itself.)
+
const mDNSu8 RecordType = (mDNSu8)((i < response->h.numAnswers) ? kDNSRecordTypePacketAns : kDNSRecordTypePacketAdd);
ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting
+ // Don't want to cache OPT or TSIG pseudo-RRs
+ if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG)
+ { m->rec.r.resrec.RecordType = 0; continue; }
+
+ // When we receive uDNS LLQ responses, we assume a long cache lifetime --
+ // In the case of active LLQs, we'll get remove events when the records actually do go away
+ // In the case of polling LLQs, we assume the record remains valid until the next poll
+ if (!mDNSOpaque16IsZero(response->h.id))
+ m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl);
+
+ // If response was not sent via LL multicast,
+ // then see if it answers a recent query of ours, which would also make it acceptable for caching.
+ if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, response->h.id, &m->rec.r);
// 1. Check that this packet resource record does not conflict with any of ours
- if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set");
- m->CurrentRecord = m->ResourceRecords;
- while (m->CurrentRecord)
+ if (mDNSOpaque16IsZero(response->h.id))
{
- AuthRecord *rr = m->CurrentRecord;
- m->CurrentRecord = rr->next;
- if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match...
+ if (m->CurrentRecord)
+ LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+ m->CurrentRecord = m->ResourceRecords;
+ while (m->CurrentRecord)
{
- // ... check to see if type and rdata are identical
- if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec))
- {
- // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
- if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
- {
- // If we were planning to send on this -- and only this -- interface, then we don't need to any more
- if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
- }
- else
- {
- if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; }
- else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
- }
- }
- // else, the packet RR has different type or different rdata -- check to see if this is a conflict
- else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
+ AuthRecord *rr = m->CurrentRecord;
+ m->CurrentRecord = rr->next;
+ // We accept all multicast responses, and unicast responses resulting from queries we issued
+ // For other unicast responses, this code accepts them only for responses with an
+ // (apparently) local source address that pertain to a record of our own that's in probing state
+ if (!AcceptableResponse && !(ResponseSrcLocal && rr->resrec.RecordType == kDNSRecordTypeUnique)) continue;
+ if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match...
{
- debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr));
- debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
-
- // If this record is marked DependentOn another record for conflict detection purposes,
- // then *that* record has to be bumped back to probing state to resolve the conflict
- while (rr->DependentOn) rr = rr->DependentOn;
-
- // If we've just whacked this record's ProbeCount, don't need to do it again
- if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
+ // ... check to see if type and rdata are identical
+ if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec))
{
- // If we'd previously verified this record, put it back to probing state and try again
- if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+ // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us
+ if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState)
{
- debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
- rr->resrec.RecordType = kDNSRecordTypeUnique;
- rr->ProbeCount = DefaultProbeCountForTypeUnique + 1;
- rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
- InitializeLastAPTime(m, rr);
- RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate
+ // If we were planning to send on this -- and only this -- interface, then we don't need to any more
+ if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; }
}
- // If we're probing for this record, we just failed
- else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
+ else
{
- debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
- mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; }
+ else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
}
- // We assumed this record must be unique, but we were wrong.
- // (e.g. There are two mDNSResponders on the same machine giving
- // different answers for the reverse mapping record.)
- // This is simply a misconfiguration, and we don't try to recover from it.
- else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
+ }
+ // else, the packet RR has different type or different rdata -- check to see if this is a conflict
+ else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
+ {
+ debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr));
+ debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+
+ // If this record is marked DependentOn another record for conflict detection purposes,
+ // then *that* record has to be bumped back to probing state to resolve the conflict
+ while (rr->DependentOn) rr = rr->DependentOn;
+
+ // If we've just whacked this record's ProbeCount, don't need to do it again
+ if (rr->ProbeCount <= DefaultProbeCountForTypeUnique)
{
- debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
- rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
- mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ // If we'd previously verified this record, put it back to probing state and try again
+ if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+ {
+ debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ rr->resrec.RecordType = kDNSRecordTypeUnique;
+ rr->ProbeCount = DefaultProbeCountForTypeUnique + 1;
+ rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
+ InitializeLastAPTime(m, rr);
+ RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate
+ }
+ // If we're probing for this record, we just failed
+ else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
+ {
+ debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ }
+ // We assumed this record must be unique, but we were wrong.
+ // (e.g. There are two mDNSResponders on the same machine giving
+ // different answers for the reverse mapping record.)
+ // This is simply a misconfiguration, and we don't try to recover from it.
+ else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
+ {
+ debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
+ rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ }
+ else
+ debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
+ rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
}
- else
- debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
- rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
}
+ // Else, matching signature, different type or rdata, but not a considered a conflict.
+ // If the packet record has the cache-flush bit set, then we check to see if we
+ // have any record(s) of the same type that we should re-assert to rescue them
+ // (see note about "multi-homing and bridged networks" at the end of this function).
+ else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
+ if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
+ { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
}
- // Else, matching signature, different type or rdata, but not a considered a conflict.
- // If the packet record has the cache-flush bit set, then we check to see if we
- // have any record(s) of the same type that we should re-assert to rescue them
- // (see note about "multi-homing and bridged networks" at the end of this function).
- else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
- if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
- { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
}
}
// 2. See if we want to add this packet resource record to our cache
- if (m->rrcache_size) // Only try to cache answers if we have a cache to put them in
+ // We only try to cache answers if we have a cache to put them in
+ // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
+ if (m->rrcache_size && AcceptableResponse)
{
const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
{
// If we found this exact resource record, refresh its TTL
- if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
+ if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
{
if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
verbosedebugf("Found record size %5d interface %p already in cache: %s",
if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
{
// If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
- if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList)
+ if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events)
{ *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
// If this packet record is marked unique, and our previous cached copy was not, then fix it
}
else if (m->rec.r.resrec.rroriginalttl > 0)
{
- rr->resrec.rroriginalttl = m->rec.r.resrec.rroriginalttl;
- rr->UnansweredQueries = 0;
- rr->MPUnansweredQ = 0;
- rr->MPUnansweredKA = 0;
- rr->MPExpectingKA = mDNSfalse;
- SetNextCacheCheckTime(m, rr);
+ //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr));
+ RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
break;
}
else
// (unless it is just a deletion of a record we never had, in which case we don't care)
if (!rr && m->rec.r.resrec.rroriginalttl > 0)
{
- // If we don't have a CacheGroup for this name, make one now
- if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec);
- if (cg) rr = GetCacheRecord(m, cg, m->rec.r.resrec.rdlength); // Make a cache record, being careful not to recycle cg
- if (!rr) NoCacheAnswer(m, &m->rec.r);
- else
- {
- RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer
- *rr = m->rec.r; // Block copy the CacheRecord object
- rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
- rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
- { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
- // If this is an oversized record with external storage allocated, copy rdata to external storage
- if (rr->resrec.rdata != (RData*)&rr->rdatastorage && !(m->rec.r.resrec.rdlength > InlineCacheRDSize))
- LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
- if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
- mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength);
- rr->next = mDNSNULL; // Clear 'next' pointer
- *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list
- cg->rrcache_tail = &(rr->next); // Advance tail pointer
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) // If marked unique, assume we may have
- rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event
- else
- rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
- CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
- }
+ rr = CreateNewCacheEntry(m, slot, cg);
+ if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events)
+ { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
}
}
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
{
CacheRecord *r1 = CacheFlushRecords, *r2;
const mDNSu32 slot = HashSlot(r1->resrec.name);
- CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
+ const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
CacheFlushRecords = CacheFlushRecords->NextInCFList;
r1->NextInCFList = mDNSNULL;
+
+ // Look for records in the cache with the same signature as this new one with the cache flush
+ // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL
+ // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second.
+ // We make these TTL adjustments *only* for records that still have *more* than one second
+ // remaining to live. Otherwise, a record that we tagged for deletion half a second ago
+ // (and now has half a second remaining) could inadvertently get its life extended, by either
+ // (a) if we got an explicit goodbye packet half a second ago, the record would be considered
+ // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet,
+ // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire
+ // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it.
+ // If this were to happen repeatedly, the record's expiration could be deferred indefinitely.
+ // To avoid this, we need to ensure that the cache flushing operation will only act to
+ // *decrease* a record's remaining lifetime, never *increase* it. If a record has less than
+ // one second to go, we simply leave it alone, and leave it to expire at its assigned time.
for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
- if (SameResourceRecordSignature(&r1->resrec, &r2->resrec))
+ if (r1->resrec.InterfaceID == r2->resrec.InterfaceID &&
+ r1->resrec.rrtype == r2->resrec.rrtype &&
+ r1->resrec.rrclass == r2->resrec.rrclass)
if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
{
// If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
// else, if record is old, mark it to be flushed
if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
{
+ // If we find mismatched TTLs in an RRSet, correct them.
+ // We only do this for records with a TTL of 2 or higher. It's possible to have a
+ // goodbye announcement with the cache flush bit set (or a case change on record rdata,
+ // which we treat as a goodbye followed by an addition) and in that case it would be
+ // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
+ // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
+ // because certain early Bonjour devices are known to have this specific mismatch, and
+ // there's no point filling syslog with messages about something we already know about.
+ // We also don't log this for uDNS responses, since a caching name server is obliged
+ // to give us an aged TTL to correct for how long it has held the record,
+ // so our received TTLs are expected to vary in that case
if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
+ {
+ if (r2->resrec.rroriginalttl != 240 && r1->resrec.rroriginalttl != 60 && r2->resrec.rrtype != kDNSType_TXT &&
+ mDNSOpaque16IsZero(response->h.id))
+ LogMsg("Correcting TTL from %4d to %4d for %s",
+ r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
+ }
}
else // else, if record is old, mark it to be flushed
{
if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
}
}
+
+ // See if we need to generate negative cache entries for unanswered unicast questions
+ ptr = response->data;
+ for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
+ {
+ DNSQuestion q;
+ ptr = getQuestion(response, ptr, end, InterfaceID, &q);
+ if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q))
+ {
+ CacheRecord *rr;
+ mDNSu32 slot = HashSlot(&q.qname);
+ CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ if (SameNameRecordAnswersQuestion(&rr->resrec, &q))
+ {
+ // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
+ // 2. If we already had a negative entry which we were about to discard, then we should resurrect it
+ if (rr->resrec.rroriginalttl) break;
+ if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) break;
+ }
+
+ if (!rr || rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+ {
+ // We start off assuming a negative caching TTL of 60 seconds
+ // but then look to see if we can find an SOA authority record to tell us a better value we should be using
+ mDNSu32 negttl = 60;
+ int repeat = 0;
+ const domainname *name = &q.qname;
+ mDNSu32 hash = q.qnamehash;
+
+ // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record
+ if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL)
+ {
+ ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
+ if (ptr && m->rec.r.resrec.rrtype == kDNSType_SOA)
+ {
+ mDNSu32 ttl_s = m->rec.r.resrec.rroriginalttl < m->rec.r.resrec.rdata->u.soa.min ?
+ m->rec.r.resrec.rroriginalttl : m->rec.r.resrec.rdata->u.soa.min;
+ if (negttl < ttl_s) negttl = ttl_s;
+
+ // Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
+ // with an Authority Section SOA record for d.com, then this is a hint that the authority
+ // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either.
+ // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us
+ if (q.qtype == kDNSType_SOA)
+ {
+ int qcount = CountLabels(&q.qname);
+ int scount = CountLabels(m->rec.r.resrec.name);
+ if (qcount - 1 > scount)
+ if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name))
+ repeat = qcount - 1 - scount;
+ }
+ }
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ }
+
+ // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid
+ // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp.<domain> query),
+ // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL
+ // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist.
+ // With this fix in place, when this happens, we double the effective TTL each time (up to one hour),
+ // so that we back off our polling rate and don't keep hitting the server continually.
+ if (rr)
+ {
+ if (negttl < rr->resrec.rroriginalttl * 2)
+ negttl = rr->resrec.rroriginalttl * 2;
+ if (negttl > 3600)
+ negttl = 3600;
+ }
+
+ negttl = GetEffectiveTTL(LLQType, negttl); // Add 25% grace period if necessary
+
+ if (rr) LogOperation("Renewing negative TTL from %d to %d %s", rr->resrec.rroriginalttl, negttl, CRDisplayString(m, rr));
+
+ // If we already had a negative cache entry just update it, else make one or more new negative cache entries
+ if (rr)
+ RefreshCacheRecord(m, rr, negttl);
+ else while (1)
+ {
+ LogOperation("Making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype));
+ MakeNegativeCacheRecord(m, name, hash, q.qtype, q.qclass, negttl);
+ CreateNewCacheEntry(m, slot, cg);
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ if (!repeat) break;
+ repeat--;
+ name = (const domainname *)(name->c + 1 + name->c[0]);
+ hash = DomainNameHashValue(name);
+ slot = HashSlot(name);
+ cg = CacheGroupForName(m, slot, hash, name);
+ }
+ }
+ }
+ }
+ }
+
+mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds)
+ {
+ // Create empty resource record
+ m->rec.r.resrec.RecordType = kDNSRecordTypePacketNegative;
+ m->rec.r.resrec.InterfaceID = mDNSInterface_Any;
+ m->rec.r.resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry
+ m->rec.r.resrec.rrtype = rrtype;
+ m->rec.r.resrec.rrclass = rrclass;
+ m->rec.r.resrec.rroriginalttl = ttl_seconds;
+ m->rec.r.resrec.rdlength = 0;
+ m->rec.r.resrec.rdestimate = 0;
+ m->rec.r.resrec.namehash = namehash;
+ m->rec.r.resrec.rdatahash = 0;
+ m->rec.r.resrec.rdata = (RData*)&m->rec.r.rdatastorage;
+ m->rec.r.resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
+
+ m->rec.r.NextInKAList = mDNSNULL;
+ m->rec.r.TimeRcvd = m->timenow;
+ m->rec.r.DelayDelivery = 0;
+ m->rec.r.NextRequiredQuery = m->timenow;
+ m->rec.r.LastUsed = m->timenow;
+ m->rec.r.CRActiveQuestion = mDNSNULL;
+ m->rec.r.UnansweredQueries = 0;
+ m->rec.r.LastUnansweredTime = 0;
+ m->rec.r.MPUnansweredQ = 0;
+ m->rec.r.MPLastUnansweredQT = 0;
+ m->rec.r.MPUnansweredKA = 0;
+ m->rec.r.MPExpectingKA = mDNSfalse;
+ m->rec.r.NextInCFList = mDNSNULL;
}
mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end,
- const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
+ const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport,
const mDNSInterfaceID InterfaceID)
{
+ mDNSInterfaceID ifid = InterfaceID;
DNSMessage *msg = (DNSMessage *)pkt;
const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery;
const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
+ const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
mDNSu8 QR_OP;
mDNSu8 *ptr = mDNSNULL;
- const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
+ mDNSBool TLS = (dstaddr == (mDNSAddr *)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS
+ if (TLS) dstaddr = mDNSNULL;
-#ifndef UNICAST_DISABLED
- if (srcport.NotAnInteger == NATPMPPort.NotAnInteger)
+#ifndef UNICAST_DISABLED
+ if (mDNSSameAddress(srcaddr, &m->Router))
{
- mDNS_Lock(m);
- uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
- mDNS_Unlock(m);
- return;
+ if (mDNSSameIPPort(srcport, NATPMPPort))
+ {
+ mDNS_Lock(m);
+ uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
+ mDNS_Unlock(m);
+ return;
+ }
+#ifdef _LEGACY_NAT_TRAVERSAL_
+ if (mDNSSameIPPort(srcport, SSDPPort))
+ {
+ mDNS_Lock(m);
+ LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
+ mDNS_Unlock(m);
+ return;
+ }
+#endif
}
-#endif
+#endif
if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; }
QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
ptr = (mDNSu8 *)&msg->h.numQuestions;
- msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
- msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
- msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
- msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
+ msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+ msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
+ msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
+ msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; }
// We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
// If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
- if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
+ if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
mDNS_Lock(m);
m->PktNum++;
#ifndef UNICAST_DISABLED
- if (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdateR))
- uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
+ if (!dstaddr || (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdR)))
+ {
+ if (!mDNSOpaque16IsZero(msg->h.id)) ifid = mDNSInterface_Any;
+ if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG)
+ DumpPacket(m, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, msg, end);
+ uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
// Note: mDNSCore also needs to get access to received unicast responses
-#endif
- if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
- else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
- else if (QR_OP != UpdateR)
+ }
+#endif
+ if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
+ else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
+ else if (QR_OP != UpdR)
+ {
LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)",
msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID);
-
+ }
// Packet reception often causes a change to the task list:
// 1. Inbound queries can cause us to need to send responses
// 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
-#pragma mark -
#pragma mark - Searcher Functions
#endif
-#define SameQTarget(A,B) (mDNSSameAddress(&(A)->Target, &(B)->Target) && (A)->TargetPort.NotAnInteger == (B)->TargetPort.NotAnInteger)
+// Targets are considered the same if both queries are untargeted, or
+// if both are targeted to the same address+port
+// (If Target address is zero, TargetPort is undefined)
+#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
+ (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
{
// This prevents circular references, where two questions are each marked as a duplicate of the other.
// Accordingly, we break out of the loop when we get to 'question', because there's no point searching
// further in the list.
- for (q = m->Questions; q && q != question; q=q->next) // Scan our list of questions
- if (q->InterfaceID == question->InterfaceID && // for another question with the same InterfaceID,
+ for (q = m->Questions; q && q != question; q=q->next) // Scan our list for another question
+ if (q->InterfaceID == question->InterfaceID && // with the same InterfaceID,
SameQTarget(q, question) && // and same unicast/multicast target settings
q->qtype == question->qtype && // type,
q->qclass == question->qclass && // class,
+ q->AuthInfo == question->AuthInfo && // and privacy status matches
+ q->LongLived == question->LongLived && // and long-lived status matches
q->qnamehash == question->qnamehash &&
SameDomainName(&q->qname, &question->qname)) // and name
return(q);
return(mDNSNULL);
}
-// This is called after a question is deleted, in case other identical questions were being
-// suppressed as duplicates
-mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const question)
+// This is called after a question is deleted, in case other identical questions were being
+// suppressed as duplicates
+mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question)
+ {
+ DNSQuestion *q;
+ for (q = m->Questions; q; q=q->next) // Scan our list of questions
+ if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate
+ if ((q->DuplicateOf = FindDuplicateQuestion(m, q)) == mDNSNULL)
+ {
+ // If q used to be a duplicate, but now is not,
+ // then inherit the state from the question that's going away
+ q->LastQTime = question->LastQTime;
+ q->ThisQInterval = question->ThisQInterval;
+ q->ExpectUnicastResp = question->ExpectUnicastResp;
+ q->LastAnswerPktNum = question->LastAnswerPktNum;
+ q->RecentAnswerPkts = question->RecentAnswerPkts;
+ q->RequestUnicast = question->RequestUnicast;
+ q->LastQTxTime = question->LastQTxTime;
+ q->CNAMEReferrals = question->CNAMEReferrals;
+ q->nta = question->nta;
+ q->servAddr = question->servAddr;
+ q->servPort = question->servPort;
+
+ q->state = question->state;
+ // q->NATInfoUDP = question->NATInfoUDP;
+ q->eventPort = question->eventPort;
+ // q->tcp = question->tcp;
+ q->origLease = question->origLease;
+ q->expire = question->expire;
+ q->ntries = question->ntries;
+ q->id = question->id;
+
+ question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question
+ // question->NATInfoUDP = mDNSNULL;
+ // question->tcp = mDNSNULL;
+ if (q->nta)
+ {
+ LogOperation("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->nta->ZoneDataContext = q;
+ }
+
+ // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash
+ if (question->tcp) LogOperation("UpdateQuestionDuplicates did not transfer tcp pointer");
+
+ SetNextQueryTime(m,q);
+ }
+ }
+
+// lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful
+mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name)
+ {
+ DNSServer *curmatch = mDNSNULL, *p;
+ int curmatchlen = -1, ncount = name ? CountLabels(name) : 0;
+
+ for (p = m->DNSServers; p; p = p->next)
+ {
+ int scount = CountLabels(&p->domain);
+ if (!p->del && ncount >= scount && scount > curmatchlen)
+ if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain))
+ { curmatch = p; curmatchlen = scount; }
+ }
+ return(curmatch);
+ }
+
+#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
+ (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
+
+mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question)
{
- DNSQuestion *q;
- for (q = m->Questions; q; q=q->next) // Scan our list of questions
- if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate
+ // For now this AutoTunnel stuff is specific to Mac OS X.
+ // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
+#if APPLE_OSX_mDNSResponder
+ if (question->qtype == kDNSType_AAAA && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
+ {
+ question->NoAnswer = NoAnswer_Suspended;
+ AddNewClientTunnel(m, question);
+ return;
+ }
+#endif // APPLE_OSX_mDNSResponder
+
+ if (!question->DuplicateOf)
+ {
+ if (question->LongLived)
{
- q->ThisQInterval = question->ThisQInterval;
- q->RequestUnicast = question->RequestUnicast;
- q->LastQTime = question->LastQTime;
- q->RecentAnswerPkts = 0;
- q->DuplicateOf = FindDuplicateQuestion(m, q);
- q->LastQTxTime = question->LastQTxTime;
- SetNextQueryTime(m,q);
+ question->ThisQInterval = 0; // Question is suspended, waiting for GetZoneData to complete
+ question->LastQTime = m->timenow;
+ LogOperation("uDNS_InitLongLivedQuery: %##s %s %s %d",
+ question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? "(Private)" : "", question->ThisQInterval);
+ if (question->nta) CancelGetZoneData(m, question->nta);
+ question->state = LLQ_GetZoneInfo; // Necessary to stop "bad state" error in startLLQHandshakeCallback
+ question->nta = StartGetZoneData(m, &question->qname, ZoneServiceLLQ, startLLQHandshakeCallback, question);
+ if (!question->nta) LogMsg("ERROR: startLLQ - StartGetZoneData failed");
+ }
+ else
+ {
+ question->ThisQInterval = InitialQuestionInterval;
+ question->LastQTime = m->timenow - question->ThisQInterval;
}
+ }
}
-#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
- ((Q)->TargetPort.NotAnInteger == UnicastDNSPort.NotAnInteger || (Q)->TargetPort.NotAnInteger == MulticastDNSPort.NotAnInteger))
-
-mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
+mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
{
if (question->Target.type && !ValidQuestionTarget(question))
{
question->TargetQID = zeroID;
}
-#ifndef UNICAST_DISABLED
+#ifndef UNICAST_DISABLED
// If the client has specified 'kDNSServiceFlagsForceMulticast'
// then we do a multicast query on that interface, even for unicast domains.
- if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
- question->uDNS_info.id = zeroID;
- else return uDNS_StartQuery(m, question);
+ if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
+ question->TargetQID = zeroID;
+ else
+ question->TargetQID = mDNS_NewMessageID(m);
#else
- question->uDNS_info.id = zeroID;
+ question->TargetQID = zeroID;
#endif // UNICAST_DISABLED
-
- //LogOperation("mDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-
+
+ debugf("mDNS_StartQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+
if (m->rrcache_size == 0) // Can't do queries if we have no cache space allocated
return(mStatus_NoCache);
else
{
int i;
+ DNSQuestion **q;
+
+ if (!ValidateDomainName(&question->qname))
+ {
+ LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+ return(mStatus_Invalid);
+ }
+
// Note: It important that new questions are appended at the *end* of the list, not prepended at the start
- DNSQuestion **q = &m->Questions;
+ q = &m->Questions;
if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
while (*q && *q != question) q=&(*q)->next;
return(mStatus_AlreadyRegistered);
}
- // If this question is referencing a specific interface, make sure it exists
+ *q = question;
+
+ // If this question is referencing a specific interface, verify it exists
if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly)
{
NetworkInterfaceInfo *intf;
for (intf = m->HostInterfaces; intf; intf = intf->next)
if (intf->InterfaceID == question->InterfaceID) break;
if (!intf)
- {
- debugf("mDNS_StartQuery_internal: Question %##s InterfaceID %p not found", question->qname.c, question->InterfaceID);
- return(mStatus_BadInterfaceErr);
- }
- }
-
- if (!ValidateDomainName(&question->qname))
- {
- LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- return(mStatus_Invalid);
+ LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list",
+ question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
}
// Note: In the case where we already have the answer to this question in our cache, that may be all the client
// wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
- // be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds
- // that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately.
- if (!m->RandomQueryDelay) m->RandomQueryDelay = 1 + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
-
- question->next = mDNSNULL;
- question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion()
- question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
- question->ThisQInterval = InitialQuestionInterval * 2; // MUST be > zero for an active question
- question->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
- question->LastQTime = m->timenow - m->RandomQueryDelay; // Avoid inter-machine synchronization
- question->LastAnswerPktNum = m->PktNum;
- question->RecentAnswerPkts = 0;
- question->CurrentAnswers = 0;
- question->LargeAnswers = 0;
- question->UniqueAnswers = 0;
- question->DuplicateOf = FindDuplicateQuestion(m, question);
- question->NextInDQList = mDNSNULL;
+ // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval).
+ // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate
+ // that to go out immediately.
+ question->next = mDNSNULL;
+ question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion()
+ question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
+ question->LastQTime = m->timenow;
+ question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
+ question->ExpectUnicastResp = 0;
+ question->LastAnswerPktNum = m->PktNum;
+ question->RecentAnswerPkts = 0;
+ question->CurrentAnswers = 0;
+ question->LargeAnswers = 0;
+ question->UniqueAnswers = 0;
+ question->FlappingInterface1 = mDNSNULL;
+ question->FlappingInterface2 = mDNSNULL;
+ // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately,
+ // because that would result in an infinite loop (i.e. to do a private query we first need to get
+ // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so
+ // we'd need to already know the _dns-query-tls SRV record.
+ // Also: Make sure we set AuthInfo before calling FindDuplicateQuestion()
+ question->AuthInfo = (question->QuestionCallback == GetZoneData_QuestionCallback) ? mDNSNULL
+ : GetAuthInfoForName_internal(m, &question->qname);
+ question->DuplicateOf = FindDuplicateQuestion(m, question);
+ question->NextInDQList = mDNSNULL;
+ question->SendQNow = mDNSNULL;
+ question->SendOnAll = mDNSfalse;
+ question->RequestUnicast = 0;
+ question->LastQTxTime = m->timenow;
+ question->CNAMEReferrals = 0;
+
+ question->qDNSServer = mDNSNULL;
+ question->nta = mDNSNULL;
+ question->servAddr = zeroAddr;
+ question->servPort = zeroIPPort;
+ question->tcp = mDNSNULL;
+ question->NoAnswer = NoAnswer_Normal;
+
+ question->state = LLQ_GetZoneInfo;
+ mDNSPlatformMemZero(&question->NATInfoUDP, sizeof(question->NATInfoUDP));
+ question->eventPort = zeroIPPort;
+ question->origLease = 0;
+ question->expire = 0;
+ question->ntries = 0;
+ question->id = zeroOpaque64;
+
for (i=0; i<DupSuppressInfoSize; i++)
question->DupSuppress[i].InterfaceID = mDNSNULL;
- // question->InterfaceID must be already set by caller
- question->SendQNow = mDNSNULL;
- question->SendOnAll = mDNSfalse;
- question->LastQTxTime = m->timenow;
if (!question->DuplicateOf)
- verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) started",
- question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question->LastQTime + question->ThisQInterval - m->timenow, question);
+ debugf("mDNS_StartQuery: Question %##s (%s) %p %d (%p) started",
+ question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
+ question->LastQTime + question->ThisQInterval - m->timenow, question);
else
- verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) duplicate of (%p)",
- question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf);
+ debugf("mDNS_StartQuery: Question %##s (%s) %p %d (%p) duplicate of (%p)",
+ question->qname.c, DNSTypeName(question->qtype), question->InterfaceID,
+ question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf);
- *q = question;
if (question->InterfaceID == mDNSInterface_LocalOnly)
{
if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
else
{
if (!m->NewQuestions) m->NewQuestions = question;
+
+ // If the question's id is non-zero, then it's Wide Area
+ // MUST NOT do this Wide Area setup until near the end of
+ // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA,
+ // NS, etc.) and if we haven't finished setting up our own question and setting
+ // m->NewQuestions if necessary then we could end up recursively re-entering
+ // this routine with the question list data structures in an inconsistent state.
+ if (!mDNSOpaque16IsZero(question->TargetQID))
+ {
+ question->qDNSServer = GetServerForName(m, &question->qname);
+ ActivateUnicastQuery(m, question);
+ }
SetNextQueryTime(m,question);
}
}
}
-mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
+// CancelGetZoneData is an internal routine (i.e. must be called with the lock already held)
+mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
+ {
+ LogOperation("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype));
+ mDNS_StopQuery_internal(m, &nta->question);
+ mDNSPlatformMemFree(nta);
+ }
+
+mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
{
const mDNSu32 slot = HashSlot(&question->qname);
CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
CacheRecord *rr;
DNSQuestion **q = &m->Questions;
-
- if (uDNS_IsActiveQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question);
+ //LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+
if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
while (*q && *q != question) q=&(*q)->next;
if (*q) *q = (*q)->next;
if (question->ThisQInterval >= 0) // Only log error message if the query was supposed to be active
LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list",
question->qname.c, DNSTypeName(question->qtype));
+#if ForceAlerts
+ *(long*)0 = 0;
+#endif
return(mStatus_BadReferenceErr);
}
// But don't trash ThisQInterval until afterwards.
question->ThisQInterval = -1;
- // If there are any cache records referencing this as their active question, then see if any other
- // question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
+ // If there are any cache records referencing this as their active question, then see if there is any
+ // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
{
if (rr->CRActiveQuestion == question)
for (q = m->Questions; q; q=q->next) // Scan our list of questions
if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
break;
- verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), q);
+ debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null
if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count
}
}
- // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv()is about to look at,
+ // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at,
// bump its pointer forward one question.
if (m->CurrentQuestion == question)
{
// Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
question->next = mDNSNULL;
+
+ // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype));
+
+ // And finally, cancel any associated GetZoneData operation that's still running.
+ // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list,
+ // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
+ // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
+ // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
+ if (question->nta) CancelGetZoneData(m, question->nta);
+ if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
+ if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived) uDNS_StopLongLivedQuery(m, question);
+
return(mStatus_NoError);
}
return(status);
}
-mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const rr)
+// Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs
+// Specifically, question callbacks invoked as a result of this call cannot themselves make API calls.
+// We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback
+// specifically to catch and report if the client callback does try to make API calls
+mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question)
+ {
+ mStatus status;
+ DNSQuestion *qq;
+ mDNS_Lock(m);
+
+ // Check if question is new -- don't want to give remove events for a question we haven't even answered yet
+ for (qq = m->NewQuestions; qq; qq=qq->next) if (qq == question) break;
+
+ status = mDNS_StopQuery_internal(m, question);
+ if (status == mStatus_NoError && !qq)
+ {
+ CacheRecord *rr;
+ const mDNSu32 slot = HashSlot(&question->qname);
+ CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
+ LogOperation("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
+ {
+ // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
+ if (question->QuestionCallback)
+ question->QuestionCallback(m, question, &rr->resrec, mDNSfalse);
+ }
+ }
+ mDNS_Unlock(m);
+ return(status);
+ }
+
+mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr)
{
mStatus status;
mDNS_Lock(m);
- status = mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
+ status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+ if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
mDNS_Unlock(m);
return(status);
}
CacheRecord *cr;
mDNS_Lock(m);
cr = FindIdenticalRecordInCache(m, rr);
+ debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr));
if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+ if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0);
mDNS_Unlock(m);
return(status);
}
question->LongLived = mDNSfalse;
question->ExpectUnique = mDNSfalse;
question->ForceMCast = ForceMCast;
+ question->ReturnIntermed = mDNSfalse;
question->QuestionCallback = Callback;
question->QuestionContext = Context;
if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
#ifndef UNICAST_DISABLED
- if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname))
- {
- question->LongLived = mDNSfalse;
- question->uDNS_info.id = zeroID;
- return(mDNS_StartQuery(m, question));
- }
- else
+ if (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname))
{
- mStatus status;
- // Need to explicitly lock here, because mDNS_StartQuery does locking but uDNS_StartQuery does not
- mDNS_Lock(m);
- question->LongLived = mDNStrue;
- status = uDNS_StartQuery(m, question);
- mDNS_Unlock(m);
- return(status);
+ question->LongLived = mDNStrue;
+ question->ThisQInterval = InitialQuestionInterval;
+ question->LastQTime = m->timenow - question->ThisQInterval;
}
-#else
- return(mDNS_StartQuery(m, question));
#endif // UNICAST_DISABLED
+ return(mDNS_StartQuery(m, question));
}
mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m)
return(mDNSfalse);
}
-mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
- mDNSBool PortChanged = (mDNSBool)(query->info->port.NotAnInteger != answer->rdata->u.srv.port.NotAnInteger);
+ mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port);
if (!AddRecord) return;
if (answer->rrtype != kDNSType_SRV) return;
query->qAv6.InterfaceID = answer->InterfaceID;
AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
}
- debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c);
+ debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype));
mDNS_StartQuery(m, &query->qAv4);
// Only do the AAAA query if this machine actually has IPv6 active
if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
// callback function is allowed to do anything, including deleting this query and freeing its memory.
}
-mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
if (!AddRecord) return;
query->GotTXT = mDNStrue;
query->info->TXTlen = answer->rdlength;
query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero
- mDNSPlatformMemCopy(answer->rdata->u.txt.c, query->info->TXTinfo, answer->rdlength);
+ mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength);
verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD);
}
}
-mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext;
//LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer));
if (query->ServiceInfoQueryCallback && query->GotTXT)
{
if (++query->Answers >= 100)
- {
- if (answer->rrtype == kDNSType_A)
- debugf("**** WARNING **** have given %lu answers for %##s (A) %.4a", query->Answers, query->qSRV.qname.c, &answer->rdata->u.ipv4);
- else
- debugf("**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", query->Answers, query->qSRV.qname.c, &answer->rdata->u.ipv6);
- }
+ debugf(answer->rrtype == kDNSType_A ?
+ "**** WARNING **** have given %lu answers for %##s (A) %.4a" :
+ "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a",
+ query->Answers, query->qSRV.qname.c, &answer->rdata->u.data);
query->ServiceInfoQueryCallback(m, query);
}
}
query->qSRV.LongLived = mDNSfalse;
query->qSRV.ExpectUnique = mDNStrue;
query->qSRV.ForceMCast = mDNSfalse;
+ query->qSRV.ReturnIntermed = mDNSfalse;
query->qSRV.QuestionCallback = FoundServiceInfoSRV;
query->qSRV.QuestionContext = query;
query->qTXT.LongLived = mDNSfalse;
query->qTXT.ExpectUnique = mDNStrue;
query->qTXT.ForceMCast = mDNSfalse;
+ query->qTXT.ReturnIntermed = mDNSfalse;
query->qTXT.QuestionCallback = FoundServiceInfoTXT;
query->qTXT.QuestionContext = query;
query->qAv4.LongLived = mDNSfalse;
query->qAv4.ExpectUnique = mDNStrue;
query->qAv4.ForceMCast = mDNSfalse;
+ query->qAv4.ReturnIntermed = mDNSfalse;
query->qAv4.QuestionCallback = FoundServiceInfo;
query->qAv4.QuestionContext = query;
query->qAv6.LongLived = mDNSfalse;
query->qAv6.ExpectUnique = mDNStrue;
query->qAv6.ForceMCast = mDNSfalse;
+ query->qAv6.ReturnIntermed = mDNSfalse;
query->qAv6.QuestionCallback = FoundServiceInfo;
query->qAv6.QuestionContext = query;
{
mDNS_Lock(m);
// We use mDNS_StopQuery_internal here because we're already holding the lock
- if (q->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qSRV, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qSRV);
- if (q->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qTXT, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qTXT);
- if (q->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv4, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv4);
- if (q->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv6, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv6);
+ if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV);
+ if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT);
+ if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4);
+ if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6);
mDNS_Unlock(m);
}
question->LongLived = mDNSfalse;
question->ExpectUnique = mDNSfalse;
question->ForceMCast = mDNSfalse;
+ question->ReturnIntermed = mDNSfalse;
question->QuestionCallback = Callback;
question->QuestionContext = Context;
if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
#endif
if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
- { LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer)); return(mStatus_Invalid); }
+ {
+ LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
+ return(mStatus_Invalid);
+ }
mDNS_Lock(m);
if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
- if (rr->resrec.rroriginalttl == newttl && rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
+ if (rr->resrec.rroriginalttl == newttl &&
+ rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
CompleteRDataUpdate(m, rr);
else
{
if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
rr->ThisAPInterval *= 4;
rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
- LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", rr->resrec.name->c, delay, delay > 1 ? "s" : "");
+ LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s",
+ rr->resrec.name->c, delay, delay > 1 ? "s" : "");
}
rr->resrec.rroriginalttl = newttl;
}
return(status);
}
-mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+// Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
+mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
{
mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
{
- char buffer[256];
+ char buffer[MAX_REVERSE_MAPPING_NAME];
NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m);
if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
#endif
// 1. Set up Address record to map from host name ("foo.local.") to IP address
// 2. Set up reverse-lookup PTR record to map from our address back to our host name
- AssignDomainName(set->RR_A.resrec.name, &m->MulticastHostname);
+ AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname);
if (set->ip.type == mDNSAddrType_IPv4)
{
set->RR_A.resrec.rrtype = kDNSType_A;
set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
- // Note: This is reverse order compared to a normal dotted-decimal IP address
+ // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
}
mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
}
- MakeDomainNameFromDNSNameString(set->RR_PTR.resrec.name, buffer);
- set->RR_PTR.HostTarget = mDNStrue; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
- set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
+ MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer);
+ set->RR_PTR.AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
+ set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
- set->RR_A.RRSet = &primary->RR_A; // May refer to self
+ set->RR_A.RRSet = &primary->RR_A; // May refer to self
mDNS_Register_internal(m, &set->RR_A);
mDNS_Register_internal(m, &set->RR_PTR);
- if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
+ if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
{
mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
- AssignDomainName(set->RR_HINFO.resrec.name, &m->MulticastHostname);
+ AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname);
set->RR_HINFO.DependentOn = &set->RR_A;
- mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]);
+ mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
p += 1 + (int)p[0];
- mDNSPlatformMemCopy(&m->HISoftware, p, 1 + (mDNSu32)m->HISoftware.c[0]);
+ mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
mDNS_Register_internal(m, &set->RR_HINFO);
}
else
if (!AppendDomainLabel(&newmname, &m->hostlabel)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; }
- if (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
+ if (SameDomainNameCS(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
mDNS_Lock(m);
- AssignDomainName(&m->MulticastHostname, &newmname);
+ AssignDomainName(&m->MulticastHostname, &newmname);
// 1. Stop advertising our address records on all interfaces
for (intf = m->HostInterfaces; intf; intf = intf->next)
if (intf->Advertise) DeadvertiseInterface(m, intf);
// 3. Make sure that any SRV records (and the like) that reference our
// host name in their rdata get updated to reference this new host name
- for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
- for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr);
-
+ for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
+ for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr);
+
mDNS_Unlock(m);
}
-mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
(void)rr; // Unused parameter
{
// Notify the client that the host name is successfully registered
if (m->MainCallback)
- {
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- m->MainCallback(m, result);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- }
+ m->MainCallback(m, mStatus_NoError);
}
else if (result == mStatus_NameConflict)
{
// 1. First give the client callback a chance to pick a new name
if (m->MainCallback)
- {
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
m->MainCallback(m, mStatus_NameConflict);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- }
// 2. If the client callback didn't do it, add (or increment) an index ourselves
- if (SameDomainLabel(m->hostlabel.c, oldlabel.c))
+ // This needs to be case-insensitive compare, because we need to know that the name has been changed so as to
+ // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again.
+ if (SameDomainLabelCS(m->hostlabel.c, oldlabel.c))
IncrementLabelSuffix(&m->hostlabel, mDNSfalse);
// 3. Generate the FQDNs from the hostlabel,
}
}
-mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay)
+mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
{
mDNSBool FirstOfType = mDNStrue;
NetworkInterfaceInfo **p = &m->HostInterfaces;
mDNS_Lock(m);
- // Assume this interface will be active
+ // Assume this interface will be active now, unless we find a duplicate already in the list
set->InterfaceActive = mDNStrue;
set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
+ // Scan list to see if this InterfaceID is already represented
while (*p)
{
if (*p == set)
return(mStatus_AlreadyRegistered);
}
- // This InterfaceID is already in the list, so mark this interface inactive for now
if ((*p)->InterfaceID == set->InterfaceID)
{
+ // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now
set->InterfaceActive = mDNSfalse;
if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse;
if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue;
if (set->Advertise)
AdvertiseInterface(m, set);
- debugf("mDNS_RegisterInterface: InterfaceID %p %#a %s", set->InterfaceID, &set->ip,
+ LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip,
set->InterfaceActive ?
"not represented in list; marking active and retriggering queries" :
"already represented in list; marking inactive for now");
- // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
+ // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
// giving the false impression that there's an active representative of this interface when there really isn't.
// Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
// even if we believe that we previously had an active representative of this interface.
{
DNSQuestion *q;
AuthRecord *rr;
- mDNSs32 initial = InitialQuestionInterval;
+ // If flapping, delay between first and second queries is eight seconds instead of one
+ mDNSs32 delay = flapping ? mDNSPlatformOneSecond * 5 : 0;
+ mDNSu8 announce = flapping ? (mDNSu8)1 : InitialAnnounceCount;
// Use a small amount of randomness:
- // In the case of a network administrator turning on an Ethernet hub so that all the connected machines establish link at
- // exactly the same time, we don't want them to all go and hit the network with identical queries at exactly the same moment.
+ // In the case of a network administrator turning on an Ethernet hub so that all the
+ // connected machines establish link at exactly the same time, we don't want them all
+ // to go and hit the network with identical queries at exactly the same moment.
if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
- if (delay)
+ if (flapping)
{
- LogMsg("Repeated transitions for interface %s (%#a); delaying packets by %d seconds",
- set->ifname, &set->ip, delay/mDNSPlatformOneSecond);
- initial = InitialQuestionInterval * 8; // Delay between first and second queries is eight seconds
+ LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip);
if (!m->SuppressProbes ||
m->SuppressProbes - (m->timenow + delay) < 0)
m->SuppressProbes = (m->timenow + delay);
}
- for (q = m->Questions; q; q=q->next) // Scan our list of questions
- if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
- { // then reactivate this question
- q->ThisQInterval = initial; // MUST be > zero for an active question
- q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
- q->LastQTime = m->timenow - q->ThisQInterval + delay;
- q->RecentAnswerPkts = 0;
- SetNextQueryTime(m,q);
- }
+
+ for (q = m->Questions; q; q=q->next) // Scan our list of questions
+ if (mDNSOpaque16IsZero(q->TargetQID))
+ if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
+ { // then reactivate this question
+ mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
+ mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
+ mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0;
+ if (dodelay) LogOperation("No cache records for expired %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
+
+ if (!q->ThisQInterval || q->ThisQInterval > initial)
+ {
+ q->ThisQInterval = initial;
+ q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it
+ }
+ q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
+ q->RecentAnswerPkts = 0;
+ SetNextQueryTime(m,q);
+ }
// For all our non-specific authoritative resource records (and any dormant records specific to this interface)
// we now need them to re-probe if necessary, and then re-announce.
{
if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType);
- rr->AnnounceCount = delay ? (mDNSu8)1 : InitialAnnounceCount;
+ if (rr->AnnounceCount < announce) rr->AnnounceCount = announce;
rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
InitializeLastAPTime(m, rr);
}
// NOTE: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
// the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
-mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set)
+mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
{
NetworkInterfaceInfo **p = &m->HostInterfaces;
break;
if (intf)
{
- debugf("mDNS_DeregisterInterface: Another representative of InterfaceID %p exists; making it active",
- set->InterfaceID);
+ LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;"
+ " making it active", set->InterfaceID, set->ifname, &set->ip);
intf->InterfaceActive = mDNStrue;
UpdateInterfaceProtocols(m, intf);
CacheGroup *cg;
CacheRecord *rr;
DNSQuestion *q;
- debugf("mDNS_DeregisterInterface: Last representative of InterfaceID %p deregistered; marking questions etc. dormant",
- set->InterfaceID);
+ DNSServer *s;
+
+ LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
+ " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
- // 1. Deactivate any questions specific to this interface
+ if (flapping)
+ LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect",
+ set->ifname, &set->ip);
+
+ // 1. Deactivate any questions specific to this interface, and tag appropriate questions
+ // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
for (q = m->Questions; q; q=q->next)
- if (q->InterfaceID == set->InterfaceID)
- q->ThisQInterval = 0;
+ {
+ if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
+ if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
+ {
+ q->FlappingInterface2 = q->FlappingInterface1;
+ q->FlappingInterface1 = set->InterfaceID; // Keep history of the last two interfaces to go away
+ }
+ }
// 2. Flush any cache records received on this interface
revalidate = mDNSfalse; // Don't revalidate if we're flushing the records
FORALL_CACHERECORDS(slot, cg, rr)
if (rr->resrec.InterfaceID == set->InterfaceID)
- PurgeCacheResourceRecord(m, rr);
+ {
+ // If this interface is deemed flapping,
+ // postpone deleting the cache records in case the interface comes back again
+ if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr);
+ else
+ {
+ // We want these record to go away in 30 seconds
+ // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
+ // if the interface does come back, any relevant questions will be reactivated anyway
+ mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
+ rr->UnansweredQueries = MaxUnansweredQueries;
+ }
+ }
+
+ // 3. Any DNS servers specific to this interface are now unusable
+ for (s = m->DNSServers; s; s = s->next)
+ if (s->interface == set->InterfaceID)
+ {
+ s->interface = mDNSInterface_Any;
+ s->teststate = DNSServer_Disabled;
+ }
}
}
m->NextCacheCheck = m->timenow;
FORALL_CACHERECORDS(slot, cg, rr)
if (rr->resrec.InterfaceID == set->InterfaceID)
- mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForCableDisconnect);
+ mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
}
mDNS_Unlock(m);
sr->ServiceCallback(m, sr, result);
}
+mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
+ {
+ mDNSu32 i;
+ ServiceRecordSet **p = &m->ServiceRegistrations;
+ while (*p && *p != srs) p=&(*p)->uDNS_next;
+ if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
+
+ srs->uDNS_next = mDNSNULL;
+ *p = srs;
+
+ srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL;
+ srs->RR_TXT.resrec.rroriginalttl = kStandardTTL;
+ srs->RR_PTR.resrec.rroriginalttl = kStandardTTL;
+ for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL;
+
+ srs->srs_uselease = mDNStrue;
+
+ if (srs->RR_SRV.AutoTarget)
+ {
+ // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
+ // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
+ // with the port number in our advertised SRV record automatically tracking the external mapped port.
+ DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
+ if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP;
+ }
+
+ if (!GetServiceTarget(m, srs))
+ {
+ // defer registration until we've got a target
+ debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
+ srs->state = regState_NoTarget;
+ srs->nta = mDNSNULL;
+ return mStatus_NoError;
+ }
+
+ srs->state = regState_FetchingZoneData;
+ srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs);
+ return srs->nta ? mStatus_NoError : mStatus_NoMemoryErr;
+ }
+
// Note:
// Name is first label of domain name (any dots in the name are actual dots, not label separators)
// Type is service type (e.g. "_ipp._tcp.")
// left waiting forever looking for a nonexistent record.)
// If the host parameter is mDNSNULL or the root domain (ASCII NUL),
// then the default host name (m->MulticastHostname) is automatically used
+// If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration
mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
mStatus err;
mDNSu32 i;
+ sr->state = regState_Zero;
+ sr->srs_uselease = 0;
+ sr->expire = 0;
+ sr->TestForSelfConflict = 0;
+ sr->Private = 0;
+ sr->id = zeroID;
+ sr->zone.c[0] = 0;
+ sr->ns = zeroAddr;
+ sr->SRSUpdatePort = zeroIPPort;
+ mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo));
+ sr->ClientCallbackDeferred = 0;
+ sr->DeferredStatus = 0;
+ sr->SRVUpdateDeferred = 0;
+ sr->SRVChanged = 0;
+ sr->tcp = mDNSNULL;
+
sr->ServiceCallback = Callback;
sr->ServiceContext = Context;
+ sr->Conflict = mDNSfalse;
+
sr->Extras = mDNSNULL;
sr->NumSubTypes = NumSubTypes;
sr->SubTypes = SubTypes;
- sr->Conflict = mDNSfalse;
- if (host && host->c[0]) sr->Host = *host;
- else sr->Host.c[0] = 0;
- // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
- if (!port.NotAnInteger) return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
-
// Initialize the AuthRecord objects to sane values
+ // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out
mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr);
mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, ServiceCallback, sr);
mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, ServiceCallback, sr);
+ // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
+ if (mDNSIPPortIsZero(port))
+ return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr));
+
// If the client is registering an oversized TXT record,
// it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it
if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen)
// Set up the record names
// For now we only create an advisory record for the main type, not for subtypes
// We need to gain some operational experience before we decide if there's a need to create them for subtypes too
- if (ConstructServiceName(sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
+ if (ConstructServiceName(&sr->RR_ADV.namestorage, (const domainlabel*)"\x09_services", (const domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
return(mStatus_BadParamErr);
- if (ConstructServiceName(sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
- if (ConstructServiceName(sr->RR_SRV.resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
- AssignDomainName(sr->RR_TXT.resrec.name, sr->RR_SRV.resrec.name);
+ if (ConstructServiceName(&sr->RR_PTR.namestorage, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+ if (ConstructServiceName(&sr->RR_SRV.namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+ AssignDomainName(&sr->RR_TXT.namestorage, sr->RR_SRV.resrec.name);
// 1. Set up the ADV record rdata to advertise our service type
AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
st.c[1+st.c[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
AppendDomainName(&st, type);
mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
- if (ConstructServiceName(sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
- AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
+ if (ConstructServiceName(&sr->SubTypes[i].namestorage, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
+ AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, &sr->RR_SRV.namestorage);
sr->SubTypes[i].Additional1 = &sr->RR_SRV;
sr->SubTypes[i].Additional2 = &sr->RR_TXT;
}
sr->RR_SRV.resrec.rdata->u.srv.weight = 0;
sr->RR_SRV.resrec.rdata->u.srv.port = port;
- // Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
- if (sr->Host.c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, &sr->Host);
- else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
+ // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
+ if (host && host->c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, host);
+ else { sr->RR_SRV.AutoTarget = Target_AutoHost; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
// 4. Set up the TXT record rdata,
// and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
{
sr->RR_TXT.resrec.rdlength = txtlen;
if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr);
- mDNSPlatformMemCopy(txtinfo, sr->RR_TXT.resrec.rdata->u.txt.c, txtlen);
+ mDNSPlatformMemCopy(sr->RR_TXT.resrec.rdata->u.txt.c, txtinfo, txtlen);
}
sr->RR_TXT.DependentOn = &sr->RR_SRV;
-#ifndef UNICAST_DISABLED
+#ifndef UNICAST_DISABLED
// If the client has specified an explicit InterfaceID,
// then we do a multicast registration on that interface, even for unicast domains.
- if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
+ if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.namestorage)))
{
mStatus status;
mDNS_Lock(m);
// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
// (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
+
status = uDNS_RegisterService(m, sr);
mDNS_Unlock(m);
return(status);
return(err);
}
+mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result)
+ {
+ (void)m; // Unused
+ (void)rr; // Unused
+ (void)result; // Unused
+ LogOperation("DummyCallback %d %s", result, ARDisplayString(m, rr));
+ }
+
mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
{
mStatus status;
extra->next = mDNSNULL;
- mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
- AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name);
-
-#ifndef UNICAST_DISABLED
- if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
- {
- mDNS_Lock(m);
- // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
- // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
- // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
- // (We have to duplicate this check here because uDNS_AddRecordToService() bypasses the usual mDNS_Register_internal() bottleneck)
- if (extra->r.resrec.rrtype == kDNSType_TXT && extra->r.resrec.rdlength == 0)
- { extra->r.resrec.rdlength = 1; extra->r.resrec.rdata->u.txt.c[0] = 0; }
- status = uDNS_AddRecordToService(m, sr, extra);
- mDNS_Unlock(m);
- return status;
- }
-#endif
+ mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID,
+ extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr);
+ AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name);
mDNS_Lock(m);
e = &sr->Extras;
if (ttl == 0) ttl = kStandardTTL;
extra->r.DependentOn = &sr->RR_SRV;
-
- debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name->c);
-
+
+ debugf("mDNS_AddRecordToService adding record to %##s %s %d",
+ extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength);
+
status = mDNS_Register_internal(m, &extra->r);
- if (status == mStatus_NoError) *e = extra;
+ if (status == mStatus_NoError)
+ {
+ *e = extra;
+#ifndef UNICAST_DISABLED
+ if (sr->RR_SRV.resrec.InterfaceID != mDNSInterface_LocalOnly && !IsLocalDomain(sr->RR_SRV.resrec.name))
+ {
+ extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name (???)
+ extra->r.RecordCallback = DummyCallback; // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
+ if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued;
+ }
+#endif
+ }
+
mDNS_Unlock(m);
return(status);
}
-mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context)
+mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra,
+ mDNSRecordCallback MemFreeCallback, void *Context)
{
ExtraResourceRecord **e;
mStatus status;
extra->r.RecordCallback = MemFreeCallback;
extra->r.RecordContext = Context;
*e = (*e)->next;
-#ifndef UNICAST_DISABLED
- if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
- status = uDNS_DeregisterRecord(m, &extra->r);
- else
-#endif
status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal);
}
mDNS_Unlock(m);
// mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally.
domainlabel name1, name2;
domainname type, domain;
- domainname *host = mDNSNULL;
+ const domainname *host = sr->RR_SRV.AutoTarget ? mDNSNULL : &sr->RR_SRV.resrec.rdata->u.srv.target;
ExtraResourceRecord *extras = sr->Extras;
mStatus err;
IncrementLabelSuffix(&name2, mDNStrue);
newname = &name2;
}
- LogMsg("Service \"%##s\" renamed to \"%#s\"", sr->RR_SRV.resrec.name->c, newname->c);
- if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host;
+ if (SameDomainName(&domain, &localdomain))
+ LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
+ else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
+
err = mDNS_RegisterService(m, sr, newname, &type, &domain,
host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength,
sr->SubTypes, sr->NumSubTypes,
mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
{
// If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
- if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
+ if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
-#ifndef UNICAST_DISABLED
+#ifndef UNICAST_DISABLED
if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
{
mStatus status;
else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
{
debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
+ // Avoid race condition:
+ // If a service gets a conflict, then we set the Conflict flag to tell us to generate
+ // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
+ // If the client happens to deregister the service in the middle of that process, then
+ // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree
+ // instead of incorrectly promoting it to mStatus_NameConflict.
+ // This race condition is exposed particularly when the conformance test generates
+ // a whole batch of simultaneous conflicts across a range of services all advertised
+ // using the same system default name, and if we don't take this precaution then
+ // we end up incrementing m->nicelabel multiple times instead of just once.
+ // <rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
+ sr->Conflict = mDNSfalse;
return(mStatus_NoError);
}
else
const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
{
mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
- if (ConstructServiceName(rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+ if (ConstructServiceName(&rr->namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
rr->resrec.rdata->u.srv.priority = 0;
rr->resrec.rdata->u.srv.weight = 0;
rr->resrec.rdata->u.srv.port = zeroIPPort;
if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
- else rr->HostTarget = mDNStrue;
+ else rr->AutoTarget = Target_AutoHost;
return(mDNS_Register(m, rr));
}
mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
{
mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
- if (!MakeDomainNameFromDNSNameString(rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
+ if (!MakeDomainNameFromDNSNameString(&rr->namestorage, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname)) return(mStatus_BadParamErr);
return(mDNS_Register(m, rr));
}
+
+mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
+ {
+ static mDNSBool randomized = mDNSfalse;
+
+ if (!randomized) { m->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
+ if (m->NextMessageID == 0) m->NextMessageID++;
+ return mDNSOpaque16fromIntVal(m->NextMessageID++);
+ }
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
-#pragma mark -
#pragma mark - Startup and Shutdown
#endif
m->p = p;
m->KnownBugs = 0;
- m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
+ m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
m->AdvertiseLocalAddresses = AdvertiseLocalAddresses;
m->mDNSPlatformStatus = mStatus_Waiting;
m->UnicastPort4 = zeroIPPort;
m->NextScheduledQuery = timenow + 0x78000000;
m->NextScheduledProbe = timenow + 0x78000000;
m->NextScheduledResponse = timenow + 0x78000000;
- m->ExpectUnicastResponse = timenow + 0x78000000;
+ m->NextScheduledNATOp = timenow + 0x78000000;
m->RandomQueryDelay = 0;
+ m->RandomReconfirmDelay = 0;
m->PktNum = 0;
m->SendDeregistrations = mDNSfalse;
m->SendImmediateAnswers = mDNSfalse;
m->NumFailedProbes = 0;
m->SuppressProbes = 0;
-#ifndef UNICAST_DISABLED
- uDNS_Init(m);
+#ifndef UNICAST_DISABLED
+ m->NextuDNSEvent = timenow + 0x78000000;
+ m->NextSRVUpdate = timenow + 0x78000000;
m->SuppressStdPort53Queries = 0;
+
+ m->ServiceRegistrations = mDNSNULL;
+ m->NextMessageID = 0;
+ m->DNSServers = mDNSNULL;
+
+ m->Router = zeroAddr;
+ m->AdvertisedV4 = zeroAddr;
+ m->AdvertisedV6 = zeroAddr;
+
+ m->AuthInfoList = mDNSNULL;
+
+ m->ReverseMap.ThisQInterval = -1;
+ m->StaticHostname.c[0] = 0;
+ m->FQDN.c[0] = 0;
+ m->Hostnames = mDNSNULL;
+ m->AutoTunnelHostAddr.b[0] = 0;
+ m->AutoTunnelHostAddrActive = mDNSfalse;
+ m->AutoTunnelLabel.c[0] = 0;
+
+ m->RegisterSearchDomains = mDNSfalse;
+
+ // NAT traversal fields
+ m->NATTraversals = mDNSNULL;
+ m->CurrentNATTraversal = mDNSNULL;
+ m->retryIntervalGetAddr = 0; // delta between time sent and retry
+ m->retryGetAddr = timenow + 0x78000000; // absolute time when we retry
+ m->ExternalAddress = zerov4Addr;
+
+ m->NATMcastRecvskt = mDNSNULL;
+ m->NATMcastRecvsk2 = mDNSNULL;
+ m->LastNATupseconds = 0;
+ m->LastNATReplyLocalTime = timenow;
+
+ m->UPnPInterfaceID = 0;
+ m->UPnPRouterPort = zeroIPPort;
+ m->UPnPSOAPPort = zeroIPPort;
+ m->UPnPRouterURL = mDNSNULL;
+ m->UPnPSOAPURL = mDNSNULL;
+ m->UPnPRouterAddressString = mDNSNULL;
+ m->UPnPSOAPAddressString = mDNSNULL;
+#endif
+
+#if APPLE_OSX_mDNSResponder
+ m->TunnelClients = mDNSNULL;
#endif
+
result = mDNSPlatformInit(m);
+#ifndef UNICAST_DISABLED
+ // It's better to do this *after* the platform layer has set up the
+ // interface list and security credentials
+ uDNS_SetupDNSConfig(m); // Get initial DNS configuration
+#endif
+
return(result);
}
+mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+ {
+ (void)m; // unused
+ debugf("NameStatusCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
+ mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
+ }
+
+mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
+ {
+ mDNSu32 slot;
+ CacheGroup *cg;
+ CacheRecord *cr;
+
+ mDNSAddr v4, v6, r;
+ domainname fqdn;
+ DNSServer *ptr, **p = &m->DNSServers;
+ DNSQuestion *q;
+
+ if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m);
+
+ mDNS_Lock(m);
+
+ // Let the platform layer get the current DNS information
+ // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand
+ // (no need to hit the network with domain enumeration queries until we actually need that information).
+ for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->del = mDNStrue;
+
+ mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
+
+ // Update our qDNSServer pointers before we go and free the DNSServer object memory
+ for (q = m->Questions; q; q=q->next)
+ if (!mDNSOpaque16IsZero(q->TargetQID))
+ {
+ DNSServer *s = GetServerForName(m, &q->qname);
+ if (q->qDNSServer != s)
+ {
+ // If DNS Server for this question has changed, reactivate it
+ LogOperation("Updating DNS Server from %#a:%d to %#a:%d for %##s (%s)",
+ q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort),
+ s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort),
+ q->qname.c, DNSTypeName(q->qtype));
+ q->qDNSServer = s;
+ ActivateUnicastQuery(m, q);
+ }
+ }
+
+ while (*p)
+ {
+ if ((*p)->del)
+ {
+ // Scan our cache, looking for uDNS records that we would have queried this server for.
+ // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
+ // different DNS servers can give different answers to the same question.
+ ptr = *p;
+ ptr->del = mDNSfalse; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
+ FORALL_CACHERECORDS(slot, cg, cr)
+ if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr)
+ mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+ *p = (*p)->next;
+ mDNSPlatformMemFree(ptr);
+ }
+ else
+ p = &(*p)->next;
+ }
+
+ // If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
+ // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless
+ // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour
+ if (!m->DNSServers) FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) mDNS_PurgeCacheResourceRecord(m, cr);
+
+ // Did our FQDN change?
+ if (!SameDomainName(&fqdn, &m->FQDN))
+ {
+ if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN);
+
+ AssignDomainName(&m->FQDN, &fqdn);
+
+ if (m->FQDN.c[0])
+ {
+ mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
+ mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL);
+ }
+ }
+
+ mDNS_Unlock(m);
+
+ // handle router and primary interface changes
+ v4 = v6 = r = zeroAddr;
+ v4.type = r.type = mDNSAddrType_IPv4;
+
+ if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4))
+ {
+ mDNS_SetPrimaryInterfaceInfo(m,
+ !mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL,
+ !mDNSIPv6AddressIsZero(v6.ip.v6) ? &v6 : mDNSNULL,
+ !mDNSIPv4AddressIsZero(r .ip.v4) ? &r : mDNSNULL);
+ }
+ else
+ {
+ mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL, mDNSNULL);
+ if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
+ }
+
+ return mStatus_NoError;
+ }
+
mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
{
m->mDNSPlatformStatus = result;
if (m->MainCallback)
{
mDNS_Lock(m);
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+ mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
m->MainCallback(m, mStatus_NoError);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
mDNS_Unlock(m);
}
}
mDNSu32 rrcache_totalused = 0;
mDNSu32 slot;
NetworkInterfaceInfo *intf;
+ AuthRecord *rr;
mDNS_Lock(m);
m->mDNS_shutdown = mDNStrue;
-#ifndef UNICAST_DISABLED
- uDNS_Close(m);
+#ifndef UNICAST_DISABLED
+ uDNS_Sleep(m);
+ while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
#endif
+
rrcache_totalused = m->rrcache_totalused;
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
{
- while(m->rrcache_hash[slot])
+ while (m->rrcache_hash[slot])
{
CacheGroup *cg = m->rrcache_hash[slot];
while (cg->members)
{
- CacheRecord *rr = cg->members;
+ CacheRecord *cr = cg->members;
cg->members = cg->members->next;
- if (rr->CRActiveQuestion) rrcache_active++;
- ReleaseCacheRecord(m, rr);
+ if (cr->CRActiveQuestion) rrcache_active++;
+ ReleaseCacheRecord(m, cr);
}
cg->rrcache_tail = &cg->members;
ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
if (intf->Advertise)
DeadvertiseInterface(m, intf);
+ // Shut down all our active NAT Traversals
+ while (m->NATTraversals)
+ {
+ NATTraversalInfo *t = m->NATTraversals;
+ mDNS_StopNATOperation_internal(m, t); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process
+
+ // After stopping the NAT Traversal, we zero out the fields.
+ // This has particularly important implications for our AutoTunnel records --
+ // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
+ // handlers to just turn around and attempt to re-register those same records.
+ // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
+ t->ExternalAddress = zerov4Addr;
+ t->ExternalPort = zeroIPPort;
+ t->Lifetime = 0;
+ t->Result = mStatus_NoError;
+ }
+
// Make sure there are nothing but deregistering records remaining in the list
- if (m->CurrentRecord) LogMsg("mDNS_Close ERROR m->CurrentRecord already set");
+ if (m->CurrentRecord)
+ LogMsg("mDNS_Close ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+
+ // First we deregister any non-shared records. In particular, we want to make sure we deregister
+ // any extra records added to a Service Record Set first, before we deregister its PTR record.
m->CurrentRecord = m->ResourceRecords;
while (m->CurrentRecord)
{
- AuthRecord *rr = m->CurrentRecord;
+ rr = m->CurrentRecord;
+ if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+ else
+ m->CurrentRecord = rr->next;
+ }
+
+ // Now deregister any remaining records we didn't get the first time through
+ while (m->CurrentRecord)
+ {
+ rr = m->CurrentRecord;
if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
- {
- debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name->c);
mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
- }
else
m->CurrentRecord = rr->next;
}
// If any deregistering records remain, send their deregistration announcements before we exit
if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
else if (m->ResourceRecords) SendResponses(m);
- if (m->ResourceRecords) LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, m->ResourceRecords));
+
+ for (rr = m->ResourceRecords; rr; rr = rr->next)
+ LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, rr));
mDNS_Unlock(m);
debugf("mDNS_Close: mDNSPlatformClose");
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSDebug.h,v $
+Revision 1.36 2007/10/01 19:06:19 cheshire
+Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at
+
+Revision 1.35 2007/07/27 20:19:56 cheshire
+For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG
+
+Revision 1.34 2007/07/24 17:23:33 cheshire
+<rdar://problem/5357133> Add list validation checks for debugging
+
+Revision 1.33 2007/06/15 21:54:50 cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
+
+Revision 1.32 2007/05/25 16:03:03 cheshire
+Remove unused LogMalloc
+
+Revision 1.31 2007/04/06 19:50:05 cheshire
+Add ProgramName declaration
+
+Revision 1.30 2007/03/24 01:22:44 cheshire
+Add validator for uDNS data structures
+
+Revision 1.29 2006/08/14 23:24:23 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.28 2006/07/07 01:09:09 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
+
+Revision 1.27 2006/06/29 07:42:14 cheshire
+<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
+
+Revision 1.26 2005/07/04 22:40:26 cheshire
+Additional debugging code to help catch memory corruption
+
Revision 1.25 2004/12/14 21:34:16 cheshire
Add "#define ANSWER_REMOTE_HOSTNAME_QUERIES 0" and comment
#endif
// LogMsg is used even in shipping code, to write truly serious error messages to syslog (or equivalent)
-extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog
+typedef enum
+ {
+ MDNS_LOG_NONE,
+// MDNS_LOG_ERROR,
+// MDNS_LOG_WARN,
+// MDNS_LOG_INFO,
+// MDNS_LOG_DEBUG,
+ MDNS_LOG_VERBOSE_DEBUG
+ } LogLevel_t;
+
+#define MDNS_LOG_INITIAL_LEVEL MDNS_LOG_NONE
+
+extern LogLevel_t mDNS_LogLevel;
+extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog
+extern const char ProgramName[]; // Program Name for use with LogMsgIdent
+
extern void LogMsg(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
extern void LogMsgIdent(const char *ident, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
extern void LogMsgNoIdent(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
+extern void SigLogLevel(void);
// Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records
#define ANSWER_REMOTE_HOSTNAME_QUERIES 0
// Set this symbol to 2 to write a log message for every malloc() and free()
#define MACOSX_MDNS_MALLOC_DEBUGGING 0
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
extern void *mallocL(char *msg, unsigned int size);
extern void freeL(char *msg, void *x);
+extern void LogMemCorruption(const char *format, ...);
+extern void uds_validatelists(void);
+extern void udns_validatelists(void *const v);
#else
#define mallocL(X,Y) malloc(Y)
#define freeL(X,Y) free(Y)
#endif
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 2
-#define LogMalloc LogMsg
-#else
- #if (defined( __GNUC__ ))
- #define LogMalloc(ARGS...) ((void)0)
- #elif (defined( __MWERKS__ ))
- #define LogMalloc( ... )
- #else
- #define LogMalloc 1 ? ((void)0) : (void)
- #endif
-#endif
-
#define LogAllOperations 0
#if LogAllOperations
#define LogOperation debugf
#endif
+#define ForceAlerts 0
+
+#define VerifySameNameAssumptions 0
+
#ifdef __cplusplus
}
#endif
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
NOTE:
Change History (most recent first):
$Log: mDNSEmbeddedAPI.h,v $
-Revision 1.287 2005/10/20 00:10:33 cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-
-Revision 1.286 2005/09/24 01:09:40 cheshire
-Fix comment typos
-
-Revision 1.285 2005/09/16 20:57:47 cheshire
-Add macro mDNS_TimeNow_NoLock(m) to get properly adjusted time without also acquiring lock
-
-Revision 1.284 2005/07/29 18:04:22 ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
-
-Revision 1.283 2005/05/13 20:45:09 ksekar
-<rdar://problem/4074400> Rapid wide-area txt record updates don't work
-
-Revision 1.282 2005/03/16 00:42:32 ksekar
-<rdar://problem/4012279> Long-lived queries not working on Windows
-
-Revision 1.281 2005/02/25 17:47:44 ksekar
-<rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
-
-Revision 1.280 2005/02/25 04:21:00 cheshire
-<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
-
-Revision 1.279 2005/02/17 01:56:14 cheshire
-Increase ifname field to 64 bytes
-
-Revision 1.278 2005/02/09 23:38:51 ksekar
-<rdar://problem/3993508> Reregister hostname when DNS server changes but IP address does not
-
-Revision 1.277 2005/02/09 23:31:12 ksekar
-<rdar://problem/3984374> NAT-PMP response callback should return a boolean indicating if the packet matched the request
-
-Revision 1.276 2005/02/01 19:33:29 ksekar
-<rdar://problem/3985239> Keychain format too restrictive
-
-Revision 1.275 2005/01/27 22:57:55 cheshire
-Fix compile errors on gcc4
-
-Revision 1.274 2005/01/19 21:01:54 ksekar
-<rdar://problem/3955355> uDNS needs to support subtype registration and browsing
-
-Revision 1.273 2005/01/19 19:15:31 ksekar
-Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
-
-Revision 1.272 2005/01/18 18:10:55 ksekar
-<rdar://problem/3954575> Use 10.4 resolver API to get search domains
-
-Revision 1.271 2005/01/15 00:56:41 ksekar
-<rdar://problem/3954575> Unicast services don't disappear when logging
-out of VPN
-
-Revision 1.270 2005/01/14 18:34:22 ksekar
-<rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
-
-Revision 1.269 2005/01/11 22:50:52 ksekar
-Fixed constant naming (was using kLLQ_DefLease for update leases)
-
-Revision 1.268 2004/12/22 22:25:47 ksekar
-<rdar://problem/3734265> NAT-PMP: handle location changes
-
-Revision 1.267 2004/12/22 00:13:49 ksekar
-<rdar://problem/3873993> Change version, port, and polling interval for LLQ
-
-Revision 1.266 2004/12/18 03:13:45 cheshire
-<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
-
-Revision 1.265 2004/12/17 23:37:45 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.264 2004/12/17 05:25:46 cheshire
-<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
-
-Revision 1.263 2004/12/16 20:40:25 cheshire
-Fix compile warnings
-
-Revision 1.262 2004/12/16 20:13:00 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.261 2004/12/14 21:21:20 ksekar
-<rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
-
-Revision 1.260 2004/12/12 23:51:42 ksekar
-<rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
-
-Revision 1.259 2004/12/11 20:55:29 ksekar
-<rdar://problem/3916479> Clean up registration state machines
-
-Revision 1.258 2004/12/10 20:48:32 cheshire
-<rdar://problem/3705229> Need to pick final EDNS numbers for LLQ and GC
-
-Revision 1.257 2004/12/10 02:09:23 cheshire
-<rdar://problem/3898376> Modify default TTLs
-
-Revision 1.256 2004/12/09 03:15:40 ksekar
-<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
-
-Revision 1.255 2004/12/07 22:48:37 cheshire
-Tidying
-
-Revision 1.254 2004/12/07 21:26:04 ksekar
-<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
-
-Revision 1.253 2004/12/07 20:42:33 cheshire
-Add explicit context parameter to mDNS_RemoveRecordFromService()
-
-Revision 1.252 2004/12/07 03:02:12 ksekar
-Fixed comments, grouped unicast-specific routines together
-
-Revision 1.251 2004/12/06 21:15:22 ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.250 2004/12/04 02:12:45 cheshire
-<rdar://problem/3517236> mDNSResponder puts LargeCacheRecord on the stack
-
-Revision 1.249 2004/12/03 05:18:33 ksekar
-<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
-
-Revision 1.248 2004/12/02 20:03:48 ksekar
-<rdar://problem/3889647> Still publishes wide-area domains even after switching to a local subnet
-
-Revision 1.247 2004/12/01 20:57:19 ksekar
-<rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
+Revision 1.444 2007/09/29 03:14:52 cheshire
+<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
+Added AutoTunnelUnregistered macro to check state of DomainAuthInfo AuthRecords
-Revision 1.246 2004/11/29 23:26:32 cheshire
-Added NonZeroTime() function, which usually returns the value given, with the exception
-that if the value given is zero, it returns one instead. For timer values where zero is
-used to mean "not set", this can be used to ensure that setting them to the result of an
-interval computation (e.g. "now+interval") does not inadvertently result in a zero value.
+Revision 1.443 2007/09/27 21:21:39 cheshire
+Export CompleteDeregistration so it's callable from other files
-Revision 1.245 2004/11/25 01:28:09 cheshire
-<rdar://problem/3557050> Need to implement random delay for 'QU' unicast replies (and set cache flush bit too)
+Revision 1.442 2007/09/27 00:25:39 cheshire
+Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
+<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-Revision 1.244 2004/11/24 22:00:59 cheshire
-Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
+Revision 1.441 2007/09/26 23:17:49 cheshire
+Get rid of unused kWideAreaTTL constant
-Revision 1.243 2004/11/23 22:43:53 cheshire
-Tidy up code alignment
+Revision 1.440 2007/09/26 22:06:02 cheshire
+<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
-Revision 1.242 2004/11/23 03:39:46 cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
+Revision 1.439 2007/09/21 21:12:36 cheshire
+DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
-Revision 1.241 2004/11/22 17:16:19 ksekar
-<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+Revision 1.438 2007/09/19 20:32:09 cheshire
+Export GetAuthInfoForName so it's callable from other files
-Revision 1.240 2004/11/19 02:32:43 ksekar
-Wide-Area Security: Add LLQ-ID to events
+Revision 1.437 2007/09/18 21:42:29 cheshire
+To reduce programming mistakes, renamed ExtPort to RequestedPort
-Revision 1.239 2004/11/15 20:09:23 ksekar
-<rdar://problem/3719050> Wide Area support for Add/Remove record
+Revision 1.436 2007/09/14 21:26:08 cheshire
+<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
-Revision 1.238 2004/11/12 03:16:48 rpantos
-rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
+Revision 1.435 2007/09/13 00:16:41 cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-Revision 1.237 2004/11/10 20:40:53 ksekar
-<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+Revision 1.434 2007/09/12 23:03:07 cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-Revision 1.236 2004/11/01 20:36:11 ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+Revision 1.433 2007/09/12 22:19:28 cheshire
+<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
-Revision 1.235 2004/11/01 17:48:14 cheshire
-Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but
-it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page
-137. Since C doesn't have a modular type, we used signed, C's closest approximation.
+Revision 1.432 2007/09/12 19:22:19 cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-Revision 1.234 2004/10/29 21:59:02 ksekar
-SOA serial should be a unsigned integer, as per RFC 1035
+Revision 1.431 2007/09/11 19:19:16 cheshire
+Correct capitalization of "uPNP" to "UPnP"
-Revision 1.233 2004/10/28 03:24:41 cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+Revision 1.430 2007/09/10 22:06:50 cheshire
+Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
-Revision 1.232 2004/10/26 06:20:23 cheshire
-Add mDNSAddressIsValidNonZero() macro
+Revision 1.429 2007/09/07 21:16:58 cheshire
+Add new symbol "NATPMPAnnouncementPort" (5350)
-Revision 1.231 2004/10/26 06:11:41 cheshire
-Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+Revision 1.428 2007/09/05 21:48:01 cheshire
+<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
+Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs
+to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
+otherwise those records will expire and vanish from the cache.
-Revision 1.230 2004/10/26 03:52:02 cheshire
-Update checkin comments
+Revision 1.427 2007/09/05 20:47:12 cheshire
+Tidied up alignment of code layout
-Revision 1.229 2004/10/25 19:30:52 ksekar
-<rdar://problem/3827956> Simplify dynamic host name structures
+Revision 1.426 2007/09/04 20:37:06 cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+Reorder fields into more logical order, with AuthInfo before DuplicateOf
-Revision 1.228 2004/10/23 01:16:00 cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+Revision 1.425 2007/08/31 19:53:14 cheshire
+<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
+If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
-Revision 1.227 2004/10/22 20:52:07 ksekar
-<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+Revision 1.424 2007/08/31 18:49:49 vazquez
+<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
-Revision 1.226 2004/10/20 01:50:40 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Implemented ForceMCast mode for AuthRecords as well as for Questions
+Revision 1.423 2007/08/31 00:04:28 cheshire
+Added comment explaining deltime in DomainAuthInfo structure
-Revision 1.225 2004/10/19 21:33:17 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+Revision 1.422 2007/08/28 23:58:42 cheshire
+Rename HostTarget -> AutoTarget
-Revision 1.224 2004/10/16 00:16:59 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.421 2007/08/27 20:30:43 cheshire
+Only include TunnelClients list when building for OS X
-Revision 1.223 2004/10/15 23:00:17 ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
+Revision 1.420 2007/08/23 21:47:09 vazquez
+<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
+make sure we clean up port mappings on base stations by sending a lease value of 0,
+and only send NAT-PMP packets on private networks; also save some memory by
+not using packet structs in NATTraversals.
-Revision 1.222 2004/10/12 02:49:20 ksekar
-<rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
+Revision 1.419 2007/08/08 21:07:47 vazquez
+<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
-Revision 1.221 2004/10/10 06:57:15 cheshire
-Change definition of "localdomain" to make code compile a little smaller
+Revision 1.418 2007/08/01 16:09:13 cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-Revision 1.220 2004/10/06 01:44:19 cheshire
-<rdar://problem/3813936> Resolving too quickly sometimes returns stale TXT record
+Revision 1.417 2007/08/01 03:04:59 cheshire
+Add NATTraversalInfo structures to HostnameInfo and DomainAuthInfo
-Revision 1.219 2004/10/03 23:18:58 cheshire
-Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h
+Revision 1.416 2007/08/01 00:04:13 cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
-Revision 1.218 2004/10/03 23:14:12 cheshire
-Add "mDNSEthAddr" type and "zeroEthAddr" constant
+Revision 1.415 2007/07/31 02:28:35 vazquez
+<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-Revision 1.217 2004/09/30 00:24:56 ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.414 2007/07/30 23:34:19 cheshire
+Remove unused "udpSock" from DNSQuestion
-Revision 1.216 2004/09/27 23:24:32 cheshire
-Fix typo: SOA refresh interval is supposed to be unsigned
+Revision 1.413 2007/07/28 01:25:56 cheshire
+<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
-Revision 1.215 2004/09/26 23:20:35 ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.412 2007/07/27 23:57:23 cheshire
+Added compile-time structure size checks
-Revision 1.214 2004/09/25 02:41:39 cheshire
-<rdar://problem/3637266> Deliver near-pending "remove" events before new "add" events
+Revision 1.411 2007/07/27 22:50:08 vazquez
+Allocate memory for UPnP request and reply buffers instead of using arrays
-Revision 1.213 2004/09/25 02:24:27 cheshire
-Removed unused rr->UseCount
+Revision 1.410 2007/07/27 19:37:19 cheshire
+Moved AutomaticBrowseDomainQ into main mDNS object
-Revision 1.212 2004/09/24 20:57:39 cheshire
-<rdar://problem/3680902> Eliminate inappropriate casts that cause misaligned-address errors
+Revision 1.409 2007/07/27 19:30:39 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
-Revision 1.211 2004/09/24 20:33:22 cheshire
-Remove unused DNSDigest_MD5 declaration
+Revision 1.408 2007/07/27 18:44:01 cheshire
+Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
-Revision 1.210 2004/09/23 20:21:07 cheshire
-<rdar://problem/3426876> Refine "immediate answer burst; restarting exponential backoff sequence" logic
-Associate a unique sequence number with each received packet, and only increment the count of recent answer
-packets if the packet sequence number for this answer record is not one we've already seen and counted.
+Revision 1.407 2007/07/26 21:19:26 vazquez
+Retry port mapping with incremented port number (up to max) in order to handle
+port mapping conflicts on UPnP gateways
-Revision 1.209 2004/09/23 20:14:39 cheshire
-Rename "question->RecentAnswers" to "question->RecentAnswerPkts"
+Revision 1.406 2007/07/25 22:19:59 cheshire
+ClientTunnel structure also needs a rmt_outer_port field
-Revision 1.208 2004/09/23 00:50:53 cheshire
-<rdar://problem/3419452> Don't send a (DE) if a service is unregistered after wake from sleep
+Revision 1.405 2007/07/25 03:05:02 vazquez
+Fixes for:
+<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
+<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
+and a myriad of other security problems
-Revision 1.207 2004/09/22 02:34:46 cheshire
-Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h
+Revision 1.404 2007/07/24 20:22:07 cheshire
+Add AutoTunnelHostAddrActive flag
-Revision 1.206 2004/09/22 00:41:59 cheshire
-Move tcp connection status codes into the legal range allocated for mDNS use
+Revision 1.403 2007/07/24 04:14:29 cheshire
+<rdar://problem/5356281> LLQs not working in with NAT Traversal
-Revision 1.205 2004/09/21 23:40:11 ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+Revision 1.402 2007/07/21 00:54:44 cheshire
+<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
-Revision 1.204 2004/09/21 23:29:50 cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+Revision 1.401 2007/07/20 20:01:38 cheshire
+Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
-Revision 1.203 2004/09/21 20:58:22 cheshire
-Add ifname field to NetworkInterfaceInfo_struct
+Revision 1.400 2007/07/20 00:54:18 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Revision 1.202 2004/09/17 00:46:34 cheshire
-mDNS_TimeNow should take const mDNS parameter
+Revision 1.399 2007/07/18 03:22:35 cheshire
+SetupLocalAutoTunnelInterface_internal needs to be callable from uDNS.c
-Revision 1.201 2004/09/17 00:31:51 cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+Revision 1.398 2007/07/18 02:26:56 cheshire
+Don't need to declare UpdateTunnels here
-Revision 1.200 2004/09/17 00:19:10 cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+Revision 1.397 2007/07/18 01:03:50 cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+Add list of client tunnels so we can automatically reconfigure when local address changes
-Revision 1.199 2004/09/16 21:59:16 cheshire
-For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
+Revision 1.396 2007/07/16 23:54:48 cheshire
+<rdar://problem/5338850> Crash when removing or changing DNS keys
-Revision 1.198 2004/09/16 21:36:36 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-Changes to add necessary locking calls around unicast DNS operations
+Revision 1.395 2007/07/16 20:12:33 vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Revision 1.197 2004/09/16 00:24:48 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.394 2007/07/12 02:51:27 cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Revision 1.196 2004/09/14 23:42:35 cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+Revision 1.393 2007/07/11 23:43:42 cheshire
+Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
-Revision 1.195 2004/09/14 23:27:46 cheshire
-Fix compile errors
+Revision 1.392 2007/07/11 22:44:40 cheshire
+<rdar://problem/5328801> SIGHUP should purge the cache
-Revision 1.194 2004/09/10 00:49:57 cheshire
-<rdar://problem/3787644> Add error code kDNSServiceErr_Firewall, for future use
+Revision 1.391 2007/07/11 20:30:45 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Added AutoTunnelTarget and AutoTunnelService to DomainAuthInfo structure
-Revision 1.193 2004/09/03 19:23:05 ksekar
-<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+Revision 1.390 2007/07/11 18:56:55 cheshire
+Added comments about AutoTunnelHostAddr and AutoTunnelLabel
-Revision 1.192 2004/09/02 03:48:47 cheshire
-<rdar://problem/3709039> Disable targeted unicast query support by default
-1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
-2. New field AllowRemoteQuery in AuthRecord structure
-3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
-4. mDNS.c only answers remote queries if AllowRemoteQuery is set
+Revision 1.389 2007/07/11 02:44:03 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Added AutoTunnel fields to structures
-Revision 1.191 2004/08/25 00:37:27 ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+Revision 1.388 2007/07/10 01:53:18 cheshire
+<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
+AuthRecord, ServiceRecordSet, and DNSQuestion structures need tcpInfo_t pointers
+so they can keep track of what TCP connections they open
-Revision 1.190 2004/08/18 17:35:41 ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+Revision 1.387 2007/07/06 18:55:15 cheshire
+Add explicit NextScheduledNATOp scheduling variable
-Revision 1.189 2004/08/14 03:22:41 cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.386 2007/07/03 20:54:11 cheshire
+Tidied up code layout of NATTraversalInfo_struct fields and comments
-Revision 1.188 2004/08/13 23:46:58 cheshire
-"asyncronous" -> "asynchronous"
+Revision 1.385 2007/07/03 00:40:23 vazquez
+More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
+Safely deal with packet replies and client callbacks
-Revision 1.187 2004/08/13 23:37:02 cheshire
-Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
-"uDNS_info.UnicastHostname" for clarity
+Revision 1.384 2007/06/29 00:08:07 vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-Revision 1.186 2004/08/13 23:25:00 cheshire
-Now that we do both uDNS and mDNS, global replace "m->hostname" with
-"m->MulticastHostname" for clarity
+Revision 1.383 2007/06/20 01:10:12 cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-Revision 1.185 2004/08/12 00:32:36 ksekar
-<rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
+Revision 1.382 2007/06/19 20:31:59 cheshire
+Add DNSServer_Disabled state
+Add mDNSInterfaceID for DNS servers reachable over specific interfaces
-Revision 1.184 2004/08/11 17:09:31 cheshire
-Add comment clarifying the applicability of these APIs
+Revision 1.381 2007/06/15 18:11:16 cheshire
+<rdar://problem/5174466> mDNSResponder crashed in memove() near end of MobileSafari stress test
+Made AssignDomainName more defensive when source name is garbage
-Revision 1.183 2004/08/10 23:19:14 ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
+Revision 1.380 2007/05/25 00:04:51 cheshire
+Added comment explaining rdlength
-Revision 1.182 2004/07/30 17:40:06 ksekar
-<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+Revision 1.379 2007/05/21 18:04:40 cheshire
+Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
-Revision 1.181 2004/07/29 19:27:15 ksekar
-NAT-PMP Support - minor fixes and cleanup
+Revision 1.378 2007/05/17 19:11:46 cheshire
+Tidy up code layout
-Revision 1.180 2004/07/29 02:03:35 ksekar
-Delete unused #define and structure field
+Revision 1.377 2007/05/15 00:43:33 cheshire
+Remove unused regState_Cancelled
-Revision 1.179 2004/07/26 22:49:30 ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.376 2007/05/14 23:51:49 cheshire
+Added constants MAX_REVERSE_MAPPING_NAME_V4 and MAX_REVERSE_MAPPING_NAME_V6
-Revision 1.178 2004/07/13 21:24:24 rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.375 2007/05/10 21:19:18 cheshire
+Rate-limit DNS test queries to at most one per three seconds
+(useful when we have a dozen active WAB queries, and then we join a new network)
-Revision 1.177 2004/06/05 00:04:26 cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+Revision 1.374 2007/05/07 22:07:47 cheshire
+<rdar://problem/4738025> Enhance GetLargeResourceRecord to decompress more record types
-Revision 1.176 2004/06/04 08:58:29 ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
+Revision 1.373 2007/05/07 20:43:45 cheshire
+<rdar://problem/4241419> Reduce the number of queries and announcements
-Revision 1.175 2004/06/04 00:15:06 cheshire
-Move misplaced brackets
+Revision 1.372 2007/05/04 22:15:29 cheshire
+Get rid of unused q->RestartTime
-Revision 1.174 2004/06/03 23:30:16 cheshire
-Remove extraneous blank lines and white space
+Revision 1.371 2007/05/03 22:40:37 cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-Revision 1.173 2004/06/03 03:09:58 ksekar
-<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+Revision 1.370 2007/05/02 22:18:09 cheshire
+Renamed NATTraversalInfo_struct context to NATTraversalContext
-Revision 1.172 2004/06/01 23:46:50 ksekar
-<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+Revision 1.369 2007/05/01 21:21:42 cheshire
+Add missing parentheses in LEASE_OPT_RDLEN definition
-Revision 1.171 2004/05/28 23:42:37 ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.368 2007/04/30 21:33:38 cheshire
+Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
+is iterating through the m->ServiceRegistrations list
-Revision 1.170 2004/05/18 23:51:25 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.367 2007/04/28 01:31:59 cheshire
+Improve debugging support for catching memory corruption problems
-Revision 1.169 2004/05/13 04:54:20 ksekar
-Unified list copy/free code. Added symetric list for
+Revision 1.366 2007/04/27 19:28:02 cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
-Revision 1.168 2004/05/12 22:03:09 ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), implemented to return "local"
-only on non-OSX platforms. Changed call to return a copy of the list
-to avoid shared memory issues. Added a routine to free the list.
+Revision 1.365 2007/04/26 00:35:15 cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
-Revision 1.167 2004/04/22 04:07:01 cheshire
-Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it
+Revision 1.364 2007/04/24 02:07:42 cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
+Deleted some more redundant code
-Revision 1.166 2004/04/22 03:15:56 cheshire
-Fix use of "struct __attribute__((__packed__))" so it only applies on GCC >= 2.9
+Revision 1.363 2007/04/24 00:09:47 cheshire
+Remove MappedV4 field from mDNS_struct (not actually used anywhere)
-Revision 1.165 2004/04/22 03:05:28 cheshire
-kDNSClass_ANY should be kDNSQClass_ANY
+Revision 1.362 2007/04/22 06:02:02 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.164 2004/04/21 02:55:03 cheshire
-Update comments describing 'InterfaceActive' field
+Revision 1.361 2007/04/21 19:43:33 cheshire
+Code tidying: represent NAT opcodes as bitwise combinations rather than numerical additions
-Revision 1.163 2004/04/21 02:49:11 cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+Revision 1.360 2007/04/20 21:17:24 cheshire
+For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-Revision 1.162 2004/04/15 00:51:28 bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
+Revision 1.359 2007/04/19 22:50:53 cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
-Revision 1.161 2004/04/14 23:09:28 ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.358 2007/04/19 20:06:41 cheshire
+Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
-Revision 1.160 2004/04/09 17:40:26 cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
+Revision 1.357 2007/04/19 18:14:51 cheshire
+In mDNS_AddSearchDomain_CString check for NULL pointer before calling MakeDomainNameFromDNSNameString()
-Revision 1.159 2004/04/09 16:37:15 cheshire
-Suggestion from Bob Bradley:
-Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+Revision 1.356 2007/04/18 20:56:46 cheshire
+Added mDNS_AddSearchDomain_CString macro
-Revision 1.158 2004/04/02 19:38:33 cheshire
-Update comment about typical RR TTLs
+Revision 1.355 2007/04/17 19:21:29 cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
-Revision 1.157 2004/04/02 19:35:53 cheshire
-Add clarifying comments about legal mDNSInterfaceID values
+Revision 1.354 2007/04/05 22:55:34 cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-Revision 1.156 2004/04/02 19:19:48 cheshire
-Add code to do optional logging of multi-packet KA list time intervals
+Revision 1.353 2007/04/05 20:40:37 cheshire
+Remove unused mDNSPlatformTCPGetFlags()
-Revision 1.155 2004/03/24 00:29:45 ksekar
-Make it safe to call StopQuery in a unicast question callback
+Revision 1.352 2007/04/04 21:48:52 cheshire
+<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-Revision 1.154 2004/03/20 01:05:49 cheshire
-Test __LP64__ and __ILP64__ to compile properly on a wider range of 64-bit architectures
+Revision 1.351 2007/04/04 01:27:45 cheshire
+Update comment
-Revision 1.153 2004/03/13 01:57:33 ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.350 2007/04/04 00:03:26 cheshire
+<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-Revision 1.152 2004/03/09 02:27:16 cheshire
-Remove erroneous underscore in 'packed_struct' (makes no difference now, but might in future)
+Revision 1.349 2007/04/03 19:37:58 cheshire
+Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918()
-Revision 1.151 2004/03/02 03:21:56 cheshire
-<rdar://problem/3549576> Properly support "_services._dns-sd._udp" meta-queries
+Revision 1.348 2007/04/03 19:13:39 cheshire
+Added macros mDNSSameIPPort, mDNSSameOpaque16, mDNSIPPortIsZero, mDNSOpaque16IsZero
-Revision 1.150 2004/02/21 02:06:24 cheshire
-Can't use anonymous unions -- they're non-standard and don't work on all compilers
+Revision 1.347 2007/03/28 20:59:26 cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-Revision 1.149 2004/02/06 23:04:19 ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.346 2007/03/28 15:56:37 cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-Revision 1.148 2004/02/03 19:47:36 ksekar
-Added an asynchronous state machine mechanism to uDNS.c, including
-calls to find the parent zone for a domain name. Changes include code
-in repository previously dissabled via "#if 0 incomplete". Codepath
-is currently unused, and will be called to create update records, etc.
+Revision 1.345 2007/03/22 19:29:23 cheshire
+Add comment and check to ensure StandardAuthRDSize is at least 256 bytes
-Revision 1.147 2004/02/03 18:57:35 cheshire
-Update comment for "IsLocalDomain()"
+Revision 1.344 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-Revision 1.146 2004/01/30 02:20:24 bradley
-Map inline to __inline when building with Microsoft C compilers since they do not support C99 inline.
+Revision 1.343 2007/03/22 00:49:20 cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
-Revision 1.145 2004/01/29 02:59:17 ksekar
-Unicast DNS: Changed from a resource record oriented question/response
-matching to packet based matching. New callback architecture allows
-collections of records in a response to be processed differently
-depending on the nature of the request, and allows the same structure
-to be used for internal and client-driven queries with different processing needs.
+Revision 1.342 2007/03/21 23:06:00 cheshire
+Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
-Revision 1.144 2004/01/28 20:20:45 ksekar
-Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
-demux them. Check-in includes work-in-progress code, #ifdef'd out.
+Revision 1.341 2007/03/21 20:44:11 cheshire
+Added mDNSAddressIsv4LinkLocal macro
-Revision 1.143 2004/01/28 03:41:00 cheshire
-<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
+Revision 1.340 2007/03/21 00:30:02 cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
-Revision 1.142 2004/01/28 02:30:07 ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane. Stopped sending unicast messages on
-every interface. Fixed unicast resolving via mach-port API.
+Revision 1.339 2007/03/20 17:07:15 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-Revision 1.141 2004/01/27 20:15:22 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.338 2007/03/10 02:28:28 cheshire
+Added comment explaining NATResponseHndlr
-Revision 1.140 2004/01/24 23:37:08 cheshire
-At Kiren's suggestion, made functions to convert mDNSOpaque16s to/from integer values
+Revision 1.337 2007/03/10 02:02:58 cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
+Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
-Revision 1.139 2004/01/24 08:46:26 bradley
-Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs.
+Revision 1.336 2007/02/28 22:12:24 cheshire
+Get rid of unused mDNSVal32 and mDNSOpaque32fromIntVal
-Revision 1.138 2004/01/24 04:59:15 cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.335 2007/02/28 21:49:07 cheshire
+Off-by-one error: SameDomainLabelCS (case-sensitive) was stopping one character short of
+the end of the label, e.g. it would fail to detect that "chesh1" and "chesh2" are different.
-Revision 1.137 2004/01/24 03:40:56 cheshire
-Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.h so clients can use it
+Revision 1.334 2007/02/28 01:44:26 cheshire
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-Revision 1.136 2004/01/24 03:38:27 cheshire
-Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+Revision 1.333 2007/02/27 22:55:22 cheshire
+Get rid of unused AllDNSLinkGroupv4 and AllDNSLinkGroupv6
-Revision 1.135 2004/01/23 23:23:15 ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.332 2007/02/27 02:48:24 cheshire
+Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object
-Revision 1.134 2004/01/22 03:54:11 cheshire
-Create special meta-interface 'mDNSInterface_ForceMCast' (-2),
-which means "do this query via multicast, even if it's apparently a unicast domain"
+Revision 1.331 2007/02/14 03:16:39 cheshire
+<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
-Revision 1.133 2004/01/22 03:48:41 cheshire
-Make sure uDNS client doesn't accidentally use query ID zero
+Revision 1.330 2007/02/08 21:12:28 cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-Revision 1.132 2004/01/22 03:43:08 cheshire
-Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+Revision 1.329 2007/02/07 01:19:36 cheshire
+<rdar://problem/4849427> API: Reconcile conflicting error code values
-Revision 1.131 2004/01/21 21:53:18 cheshire
-<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+Revision 1.328 2007/01/25 00:19:40 cheshire
+Add CNAMEReferrals field to DNSQuestion_struct
-Revision 1.130 2003/12/14 05:05:29 cheshire
-Add comments explaining mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize
+Revision 1.327 2007/01/23 02:56:10 cheshire
+Store negative results in the cache, instead of generating them out of pktResponseHndlr()
-Revision 1.129 2003/12/13 03:05:27 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
-
-Revision 1.128 2003/12/01 21:44:23 cheshire
-Add mStatus_BadInterfaceErr = -65552 for consistency with dns_sd.h
-
-Revision 1.127 2003/12/01 18:26:37 cheshire
-Also pack the OpaqueXX union types. Otherwise, on some systems, mDNSOpaque16 is four bytes!
-
-Revision 1.126 2003/12/01 18:23:48 cheshire
-<rdar://problem/3464646>: Scalar size problem in mDNS code on some 64-bit architectures
-
-Revision 1.125 2003/11/22 00:18:27 cheshire
-Add compile-time asserts to verify correct sizes of mDNSu32, mDNSOpaque16, etc.
-
-Revision 1.124 2003/11/20 22:59:54 cheshire
-Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h
-Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work.
-
-Revision 1.123 2003/11/20 22:53:01 cheshire
-Add comment about MAX_ESCAPED_DOMAIN_LABEL
-
-Revision 1.122 2003/11/20 20:49:53 cheshire
-Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures
-
-Revision 1.121 2003/11/20 05:01:38 cheshire
-Update comments; add explanation of Advertise/DontAdvertiseLocalAddresses
-
-Revision 1.120 2003/11/14 20:59:08 cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.119 2003/11/14 19:47:52 cheshire
-Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString
-
-Revision 1.118 2003/11/14 19:18:34 cheshire
-Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
-
-Revision 1.117 2003/11/08 23:32:24 cheshire
-Gave name to anonymous struct, to avoid errors on certain compilers.
-(Thanks to ramaprasad.kr@hp.com for reporting this.)
-
-Revision 1.116 2003/11/07 03:32:56 cheshire
-<rdar://problem/3472153> mDNSResponder delivers answers in inconsistent order
-This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes
-purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is
-to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR()
-can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place.
-
-Revision 1.115 2003/09/23 00:53:54 cheshire
-NumFailedProbes should be unsigned
-
-Revision 1.114 2003/08/29 19:44:15 cheshire
-<rdar://problem/3400967> Traffic reduction: Eliminate synchronized QUs when a new service appears
-1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries
- that already have at least one unique answer in the cache
-2. For these queries, go straight to QM, skipping QU
-
-Revision 1.113 2003/08/21 19:31:58 cheshire
-Cosmetic: Swap order of fields
-
-Revision 1.112 2003/08/21 19:27:36 cheshire
-<rdar://problem/3387878> Traffic reduction: No need to announce record for longer than TTL
-
-Revision 1.111 2003/08/21 02:21:50 cheshire
-<rdar://problem/3386473> Efficiency: Reduce repeated queries
-
-Revision 1.110 2003/08/20 23:39:31 cheshire
-<rdar://problem/3344098> Review syslog messages, and remove as appropriate
-
-Revision 1.109 2003/08/19 22:24:10 cheshire
-Comment change
-
-Revision 1.108 2003/08/19 22:20:00 cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
-
-Revision 1.107 2003/08/19 06:48:25 cheshire
-<rdar://problem/3376552> Guard against excessive record updates
-Each record starts with 10 UpdateCredits.
-Every update consumes one UpdateCredit.
-UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10.
-As the number of UpdateCredits declines, the number of announcements is similarly scaled back.
-When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount.
-
-Revision 1.106 2003/08/19 04:49:28 cheshire
-<rdar://problem/3368159> Interaction between v4, v6 and dual-stack hosts not working quite right
-1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6.
-2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface.
-3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface.
-
-Revision 1.105 2003/08/19 02:33:37 cheshire
+Revision 1.326 2007/01/20 01:30:49 cheshire
Update comments
-Revision 1.104 2003/08/19 02:31:11 cheshire
-<rdar://problem/3378386> mDNSResponder overenthusiastic with final expiration queries
-Final expiration queries now only mark the question for sending on the particular interface
-pertaining to the record that's expiring.
-
-Revision 1.103 2003/08/18 19:05:44 cheshire
-<rdar://problem/3382423> UpdateRecord not working right
-Added "newrdlength" field to hold new length of updated rdata
-
-Revision 1.102 2003/08/16 03:39:00 cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
-
-Revision 1.101 2003/08/15 20:16:02 cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
- Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
- compute a hash of the rdata and store the hash in the ResourceRecord object.
-
-Revision 1.100 2003/08/14 19:29:04 cheshire
-<rdar://problem/3378473> Include cache records in SIGINFO output
-Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them
-
-Revision 1.99 2003/08/14 02:17:05 cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.98 2003/08/12 19:56:23 cheshire
-Update to APSL 2.0
-
-Revision 1.97 2003/08/12 14:59:27 cheshire
-<rdar://problem/3374490> Rate-limiting blocks some legitimate responses
-When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine
-whether to suppress the response, also check LastMCInterface to see if it matches.
-
-Revision 1.96 2003/08/12 13:57:04 cheshire
-<rdar://problem/3323817> Improve cache performance
-Changed the number of hash table slots from 37 to 499
-
-Revision 1.95 2003/08/09 00:55:02 cheshire
-<rdar://problem/3366553> mDNSResponder is taking 20-30% of the CPU
-Don't scan the whole cache after every packet.
-
-Revision 1.94 2003/08/09 00:35:29 cheshire
-
-Revision 1.93 2003/08/08 18:55:48 cheshire
-<rdar://problem/3370365> Guard against time going backwards
-
-Revision 1.92 2003/08/08 18:36:04 cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
-
-Revision 1.91 2003/08/06 21:33:39 cheshire
-Fix compiler warnings on PocketPC 2003 (Windows CE)
-
-Revision 1.90 2003/08/06 20:30:17 cheshire
-Add structure definition for rdataMX (not currently used, but good to have it for completeness)
-
-Revision 1.89 2003/08/06 18:58:19 cheshire
-Update comments
-
-Revision 1.88 2003/07/24 23:45:44 cheshire
-To eliminate compiler warnings, changed definition of mDNSBool from
-"unsigned char" to "int", since "int" is in fact truly the type that C uses
-for the result of comparison operators (a<b) and logical operators (a||b)
-
-Revision 1.87 2003/07/22 23:57:20 cheshire
-Move platform-layer function prototypes from mDNSEmbeddedAPI.h to mDNSPlatformFunctions.h where they belong
+Revision 1.325 2007/01/19 18:39:11 cheshire
+Fix a bunch of parameters that should have been declared "const"
-Revision 1.86 2003/07/20 03:52:02 ksekar
-<rdar://problem/3320722>: Feature: New DNS-SD APIs (#7875) (mDNSResponder component)
-Added error type for incompatibility between daemon and client versions
+Revision 1.324 2007/01/19 18:04:04 cheshire
+For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT
-Revision 1.85 2003/07/19 03:23:13 cheshire
-<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
+Revision 1.323 2007/01/17 21:46:02 cheshire
+Remove redundant duplicated "isPrivate" field from LLQ_Info
-Revision 1.84 2003/07/18 23:52:12 cheshire
-To improve consistency of field naming, global search-and-replace:
-NextProbeTime -> NextScheduledProbe
-NextResponseTime -> NextScheduledResponse
+Revision 1.322 2007/01/10 22:51:56 cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-Revision 1.83 2003/07/18 00:29:59 cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+Revision 1.321 2007/01/09 22:37:18 cheshire
+Provide ten-second grace period for deleted keys, to give mDNSResponder
+time to delete host name before it gives up access to the required key.
-Revision 1.82 2003/07/17 17:35:04 cheshire
-<rdar://problem/3325583> Rate-limit responses, to guard against packet flooding
+Revision 1.320 2007/01/05 08:30:41 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.81 2003/07/16 05:01:36 cheshire
-Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for
-<rdar://problem/3315761> Need to implement "unicast response" request, using top bit of qclass
+Revision 1.319 2007/01/04 23:11:11 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-Revision 1.80 2003/07/15 01:55:12 cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
+Revision 1.318 2007/01/04 20:57:48 cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-Revision 1.79 2003/07/13 02:28:00 cheshire
-<rdar://problem/3325166> SendResponses didn't all its responses
-Delete all references to RRInterfaceActive -- it's now superfluous
+Revision 1.317 2007/01/04 02:39:53 cheshire
+<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
-Revision 1.78 2003/07/13 01:47:53 cheshire
-Fix one error and one warning in the Windows build
+Revision 1.316 2006/12/22 20:59:49 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.77 2003/07/11 01:32:38 cheshire
-Syntactic cleanup (no change to funcationality): Now that we only have one host name,
-rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A".
+Revision 1.315 2006/12/20 04:07:35 cheshire
+Remove uDNS_info substructure from AuthRecord_struct
-Revision 1.76 2003/07/11 01:28:00 cheshire
-<rdar://problem/3161289> No more local.arpa
+Revision 1.314 2006/12/19 22:49:23 cheshire
+Remove uDNS_info substructure from ServiceRecordSet_struct
-Revision 1.75 2003/07/02 21:19:45 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+Revision 1.313 2006/12/19 02:38:20 cheshire
+Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
-Revision 1.74 2003/07/02 02:41:23 cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
+Revision 1.312 2006/12/19 02:18:48 cheshire
+Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
-Revision 1.73 2003/06/10 04:24:39 cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
-Some additional refinements:
-Don't try to do this for unicast-response queries
-better tracking of Qs and KAs in multi-packet KA lists
+Revision 1.311 2006/12/16 01:58:31 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
-Revision 1.72 2003/06/10 01:46:27 cheshire
-Add better comments explaining how these data structures are intended to be used from the client layer
+Revision 1.310 2006/12/15 19:09:56 cheshire
+<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
+Made DomainNameLength() more defensive by adding a limit parameter, so it can be
+safely used to inspect potentially malformed data received from external sources.
+Without this, a domain name that starts off apparently valid, but extends beyond the end of
+the received packet data, could have appeared valid if the random bytes are already in memory
+beyond the end of the packet just happened to have reasonable values (e.g. all zeroes).
-Revision 1.71 2003/06/07 06:45:05 cheshire
-<rdar://problem/3283666> No need for multiple machines to all be sending the same queries
+Revision 1.309 2006/12/14 03:02:37 cheshire
+<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-Revision 1.70 2003/06/07 04:50:53 cheshire
-<rdar://problem/3283637> React when we observe other people query unsuccessfully for a record that's in our cache
+Revision 1.308 2006/11/30 23:07:56 herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-Revision 1.69 2003/06/07 04:22:17 cheshire
-Add MsgBuffer for error log and debug messages
+Revision 1.307 2006/11/18 05:01:30 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
-Revision 1.68 2003/06/07 01:46:38 cheshire
-<rdar://problem/3283540> When query produces zero results, call mDNS_Reconfirm() on any antecedent records
+Revision 1.306 2006/11/10 07:44:04 herscher
+<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-Revision 1.67 2003/06/07 01:22:14 cheshire
-<rdar://problem/3283516> mDNSResponder needs an mDNS_Reconfirm() function
+Revision 1.305 2006/11/10 00:54:15 cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
-Revision 1.66 2003/06/07 00:59:43 cheshire
-<rdar://problem/3283454> Need some randomness to spread queries on the network
+Revision 1.304 2006/10/20 05:35:05 herscher
+<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-Revision 1.65 2003/06/06 21:41:11 cheshire
-For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines
+Revision 1.303 2006/10/04 21:37:33 herscher
+Remove uDNS_info substructure from DNSQuestion_struct
-Revision 1.64 2003/06/06 21:38:55 cheshire
-Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we
-already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.)
+Revision 1.302 2006/09/26 01:53:25 herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-Revision 1.63 2003/06/06 17:20:14 cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
+Revision 1.301 2006/09/15 21:20:15 cheshire
+Remove uDNS_info substructure from mDNS_struct
-Revision 1.62 2003/06/04 01:25:33 cheshire
-<rdar://problem/3274950> Cannot perform multi-packet known-answer suppression messages
-Display time interval between first and subsequent queries
+Revision 1.300 2006/08/14 23:24:23 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.61 2003/06/03 05:02:16 cheshire
-<rdar://problem/3277080> Duplicate registrations not handled as efficiently as they should be
+Revision 1.299 2006/07/15 02:01:28 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
-Revision 1.60 2003/05/31 00:09:49 cheshire
-<rdar://problem/3274862> Add ability to discover what services are on a network
+Revision 1.298 2006/07/05 22:55:03 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Need Private field in uDNS_RegInfo
-Revision 1.59 2003/05/29 06:11:35 cheshire
-<rdar://problem/3272214>: Report if there appear to be too many "Resolve" callbacks
+Revision 1.297 2006/07/05 22:20:03 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Revision 1.58 2003/05/29 05:48:06 cheshire
-Minor fix for when generating printf warnings: mDNS_snprintf arguments are now 3,4
+Revision 1.296 2006/06/29 05:28:01 cheshire
+Added comment about mDNSlocal and mDNSexport
-Revision 1.57 2003/05/26 03:21:27 cheshire
-Tidy up address structure naming:
-mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
+Revision 1.295 2006/06/29 03:02:43 cheshire
+<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
-Revision 1.56 2003/05/26 03:01:27 cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
+Revision 1.294 2006/06/28 06:50:08 cheshire
+In future we may want to change definition of mDNSs32 from "signed long" to "signed int"
+I doubt anyone is building mDNSResponder on systems where int is 16-bits,
+but lets add a compile-time assertion to make sure.
-Revision 1.55 2003/05/26 00:47:30 cheshire
-Comment clarification
+Revision 1.293 2006/06/12 18:00:43 cheshire
+To make code a little more defensive, check _ILP64 before _LP64,
+in case both are set by mistake on some platforms
-Revision 1.54 2003/05/24 16:39:48 cheshire
-<rdar://problem/3268631> SendResponses also needs to handle multihoming better
+Revision 1.292 2006/03/19 17:00:57 cheshire
+Define symbol MaxMsg instead of using hard-coded constant value '80'
-Revision 1.53 2003/05/23 02:15:37 cheshire
-Fixed misleading use of the term "duplicate suppression" where it should have
-said "known answer suppression". (Duplicate answer suppression is something
-different, and duplicate question suppression is yet another thing, so the use
-of the completely vague term "duplicate suppression" was particularly bad.)
+Revision 1.291 2006/03/19 02:00:07 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-Revision 1.52 2003/05/22 02:29:22 cheshire
-<rdar://problem/2984918> SendQueries needs to handle multihoming better
-Complete rewrite of SendQueries. Works much better now :-)
+Revision 1.290 2006/03/08 22:42:23 cheshire
+Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
-Revision 1.51 2003/05/21 20:14:55 cheshire
-Fix comments and warnings
-
-Revision 1.50 2003/05/14 07:08:36 cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
-
-Revision 1.49 2003/05/07 01:49:36 cheshire
-Remove "const" in ConstructServiceName prototype
-
-Revision 1.48 2003/05/07 00:18:44 cheshire
-Fix typo: "kDNSQClass_Mask" should be "kDNSClass_Mask"
-
-Revision 1.47 2003/05/06 00:00:46 cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.46 2003/04/30 20:39:09 cheshire
-Add comment
-
-Revision 1.45 2003/04/29 00:40:50 cheshire
-Fix compiler warnings
-
-Revision 1.44 2003/04/26 02:41:56 cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
-
-Revision 1.43 2003/04/25 01:45:56 cheshire
-<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
-
-Revision 1.42 2003/04/15 20:58:31 jgraessl
-
-<rdar://problem/3229014> Added a hash to lookup records in the cache.
-
-Revision 1.41 2003/04/15 18:09:13 jgraessl
-
-<rdar://problem/3228892>
-Reviewed by: Stuart Cheshire
-Added code to keep track of when the next cache item will expire so we can
-call TidyRRCache only when necessary.
-
-Revision 1.40 2003/03/29 01:55:19 cheshire
-<rdar://problem/3212360> mDNSResponder sometimes suffers false self-conflicts when it sees its own packets
-Solution: Major cleanup of packet timing and conflict handling rules
-
-Revision 1.39 2003/03/27 03:30:55 cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
- (it never really needed to deregister the interface at all)
-
-Revision 1.38 2003/03/15 04:40:36 cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.37 2003/03/14 21:34:11 cheshire
-<rdar://problem/3176950> Can't setup and print to Lexmark PS printers via Airport Extreme
-Increase size of cache rdata from 512 to 768
-
-Revision 1.36 2003/03/05 03:38:35 cheshire
-<rdar://problem/3185731> Bogus error message in console: died or deallocated, but no record of client can be found!
-Fixed by leaving client in list after conflict, until client explicitly deallocates
-
-Revision 1.35 2003/02/21 02:47:54 cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Several places in the code were calling CacheRRActive(), which searched the entire
-question list every time, to see if this cache resource record answers any question.
-Instead, we now have a field "CRActiveQuestion" in the resource record structure
-
-Revision 1.34 2003/02/21 01:54:08 cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.33 2003/02/20 06:48:32 cheshire
-<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
-
-Revision 1.32 2003/01/31 03:35:59 cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-When there were *two* active questions in the list, they were incorrectly
-finding *each other* and *both* being marked as duplicates of another question
-
-Revision 1.31 2003/01/29 02:46:37 cheshire
-Fix for IPv6:
-A physical interface is identified solely by its InterfaceID (not by IP and type).
-On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts.
-In cases where the requested outbound protocol (v4 or v6) is not supported on
-that InterfaceID, the platform support layer should simply discard that packet.
-
-Revision 1.30 2003/01/29 01:47:08 cheshire
-Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity
-
-Revision 1.29 2003/01/28 05:23:43 cheshire
-<rdar://problem/3147097> mDNSResponder sometimes fails to find the correct results
-Add 'Active' flag for interfaces
-
-Revision 1.28 2003/01/28 01:35:56 cheshire
-Revise comment about ThisQInterval to reflect new semantics
-
-Revision 1.27 2003/01/13 23:49:42 jgraessl
-Merged changes for the following fixes in to top of tree:
-<rdar://problem/3086540> computer name changes not handled properly
-<rdar://problem/3124348> service name changes are not properly handled
-<rdar://problem/3124352> announcements sent in pairs, failing chattiness test
-
-Revision 1.26 2002/12/23 22:13:28 jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.25 2002/09/21 20:44:49 zarzycki
-Added APSL info
-
-Revision 1.24 2002/09/19 23:47:35 cheshire
-Added mDNS_RegisterNoSuchService() function for assertion of non-existence
-of a particular named service
-
-Revision 1.23 2002/09/19 21:25:34 cheshire
-mDNS_snprintf() doesn't need to be in a separate file
-
-Revision 1.22 2002/09/19 04:20:43 cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.21 2002/09/17 01:06:35 cheshire
-Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init()
-
-Revision 1.20 2002/09/16 18:41:41 cheshire
-Merge in license terms from Quinn's copy, in preparation for Darwin release
+Revision 1.289 2006/02/26 00:54:41 cheshire
+Fixes to avoid code generation warning/error on FreeBSD 7
*/
#ifndef __mDNSClientAPI_h
#define __mDNSClientAPI_h
+#if defined(EFI32) || defined(EFI64)
+// EFI doesn't have stdarg.h
+#include "Tiano.h"
+#define va_list VA_LIST
+#define va_start(a, b) VA_START(a, b)
+#define va_end(a) VA_END(a)
+#define va_arg(a, b) VA_ARG(a, b)
+#else
#include <stdarg.h> // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
+#endif
+
#include "mDNSDebug.h"
#ifdef __cplusplus
#define mDNSexport
#endif
+// Explanation: These local/export markers are a little habit of mine for signaling the programmers' intentions.
+// When "mDNSlocal" is just a synonym for "static", and "mDNSexport" is a complete no-op, you could be
+// forgiven for asking what purpose they serve. The idea is that if you see "mDNSexport" in front of a
+// function definition it means the programmer intended it to be exported and callable from other files
+// in the project. If you see "mDNSlocal" in front of a function definition it means the programmer
+// intended it to be private to that file. If you see neither in front of a function definition it
+// means the programmer forgot (so you should work out which it is supposed to be, and fix it).
+// Using "mDNSlocal" instead of "static" makes it easier to do a textual searches for one or the other.
+// For example you can do a search for "static" to find if any functions declare any local variables as "static"
+// (generally a bad idea unless it's also "const", because static storage usually risks being non-thread-safe)
+// without the results being cluttered with hundreds of matches for functions declared static.
+// - Stuart Cheshire
+
// ***************************************************************************
// Structure packing macro
kDNSType_MINFO, // 14 Mailbox information
kDNSType_MX, // 15 Mail Exchanger
kDNSType_TXT, // 16 Arbitrary text string
-
- kDNSType_AAAA = 28, // 28 IPv6 address
- kDNSType_SRV = 33, // 33 Service record
- kDNSType_OPT = 41, // EDNS0 OPT record
- kDNSType_TSIG = 250, // 250 Transaction Signature
-
- kDNSQType_ANY = 255 // Not a DNS type, but a DNS query type, meaning "all types"
+ kDNSType_RP, // 17 Responsible person.
+ kDNSType_AFSDB, // 18 AFS cell database.
+ kDNSType_X25, // 19 X_25 calling address.
+ kDNSType_ISDN, // 20 ISDN calling address.
+ kDNSType_RT, // 21 Router.
+ kDNSType_NSAP, // 22 NSAP address.
+ kDNSType_NSAP_PTR, // 23 Reverse NSAP lookup (deprecated).
+ kDNSType_SIG, // 24 Security signature.
+ kDNSType_KEY, // 25 Security key.
+ kDNSType_PX, // 26 X.400 mail mapping.
+ kDNSType_GPOS, // 27 Geographical position (withdrawn).
+ kDNSType_AAAA, // 28 IPv6 Address.
+ kDNSType_LOC, // 29 Location Information.
+ kDNSType_NXT, // 30 Next domain (security).
+ kDNSType_EID, // 31 Endpoint identifier.
+ kDNSType_NIMLOC, // 32 Nimrod Locator.
+ kDNSType_SRV, // 33 Service record.
+ kDNSType_ATMA, // 34 ATM Address
+ kDNSType_NAPTR, // 35 Naming Authority PoinTeR
+ kDNSType_KX, // 36 Key Exchange
+ kDNSType_CERT, // 37 Certification record
+ kDNSType_A6, // 38 IPv6 Address (deprecated)
+ kDNSType_DNAME, // 39 Non-terminal DNAME (for IPv6)
+ kDNSType_SINK, // 40 Kitchen sink (experimentatl)
+ kDNSType_OPT, // 41 EDNS0 option (meta-RR)
+ kDNSType_APL, // 42 Address Prefix List
+ kDNSType_DS, // 43 Delegation Signer
+ kDNSType_SSHFP, // 44 SSH Key Fingerprint
+ kDNSType_IPSECKEY, // 45 IPSECKEY
+ kDNSType_RRSIG, // 46 RRSIG
+ kDNSType_NSEC, // 47 NSEC
+ kDNSType_DNSKEY, // 48 DNSKEY
+ kDNSType_DHCID, // 49 DHCID
+
+ kDNSType_TKEY = 249, // 249 Transaction key
+ kDNSType_TSIG, // 250 Transaction signature.
+ kDNSType_IXFR, // 251 Incremental zone transfer.
+ kDNSType_AXFR, // 252 Transfer zone of authority.
+ kDNSType_MAILB, // 253 Transfer mailbox records.
+ kDNSType_MAILA, // 254 Transfer mail agent records.
+ kDNSQType_ANY // Not a DNS type, but a DNS query type, meaning "all types"
} DNS_TypeValues;
// ***************************************************************************
// Macro Name __LP64__ Value 1
// A quick Google search for "defined(__LP64__)" OR "#ifdef __LP64__" gives 2590 hits and
// a search for "#if __LP64__" gives only 12, so I think we'll go with the majority and use defined()
-#if defined(_LP64) || defined(__LP64__)
-typedef signed int mDNSs32;
-typedef unsigned int mDNSu32;
-#elif defined(_ILP64) || defined(__ILP64__)
+#if defined(_ILP64) || defined(__ILP64__)
typedef signed int32 mDNSs32;
typedef unsigned int32 mDNSu32;
+#elif defined(_LP64) || defined(__LP64__)
+typedef signed int mDNSs32;
+typedef unsigned int mDNSu32;
#else
typedef signed long mDNSs32;
typedef unsigned long mDNSu32;
+//typedef signed int mDNSs32;
+//typedef unsigned int mDNSu32;
#endif
// To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct
typedef packedunion { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16;
typedef packedunion { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32;
typedef packedunion { mDNSu8 b[ 6]; mDNSu16 w[3]; mDNSu32 l[1]; } mDNSOpaque48;
+typedef packedunion { mDNSu8 b[ 8]; mDNSu16 w[4]; mDNSu32 l[2]; } mDNSOpaque64;
typedef packedunion { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128;
typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer)
// the bottom end of the range (FFFE FF00) is used for non-error values;
// Error codes:
- mStatus_UnknownErr = -65537, // First value: 0xFFFE FFFF
- mStatus_NoSuchNameErr = -65538,
- mStatus_NoMemoryErr = -65539,
- mStatus_BadParamErr = -65540,
- mStatus_BadReferenceErr = -65541,
- mStatus_BadStateErr = -65542,
- mStatus_BadFlagsErr = -65543,
- mStatus_UnsupportedErr = -65544,
- mStatus_NotInitializedErr = -65545,
- mStatus_NoCache = -65546,
- mStatus_AlreadyRegistered = -65547,
- mStatus_NameConflict = -65548,
- mStatus_Invalid = -65549,
- mStatus_Firewall = -65550,
- mStatus_Incompatible = -65551,
- mStatus_BadInterfaceErr = -65552,
- mStatus_Refused = -65553,
- mStatus_NoSuchRecord = -65554,
- mStatus_NoAuth = -65555,
- mStatus_NoSuchKey = -65556,
- mStatus_NATTraversal = -65557,
- mStatus_DoubleNAT = -65558,
- mStatus_BadTime = -65559,
- mStatus_BadSig = -65560, // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures
- mStatus_BadKey = -65561,
- mStatus_TransientErr = -65562, // transient failures, e.g. sending packets shortly after a network transition or wake from sleep
- // -65563 to -65786 currently unused; available for allocation
+ mStatus_UnknownErr = -65537, // First value: 0xFFFE FFFF
+ mStatus_NoSuchNameErr = -65538,
+ mStatus_NoMemoryErr = -65539,
+ mStatus_BadParamErr = -65540,
+ mStatus_BadReferenceErr = -65541,
+ mStatus_BadStateErr = -65542,
+ mStatus_BadFlagsErr = -65543,
+ mStatus_UnsupportedErr = -65544,
+ mStatus_NotInitializedErr = -65545,
+ mStatus_NoCache = -65546,
+ mStatus_AlreadyRegistered = -65547,
+ mStatus_NameConflict = -65548,
+ mStatus_Invalid = -65549,
+ mStatus_Firewall = -65550,
+ mStatus_Incompatible = -65551,
+ mStatus_BadInterfaceErr = -65552,
+ mStatus_Refused = -65553,
+ mStatus_NoSuchRecord = -65554,
+ mStatus_NoAuth = -65555,
+ mStatus_NoSuchKey = -65556,
+ mStatus_NATTraversal = -65557,
+ mStatus_DoubleNAT = -65558,
+ mStatus_BadTime = -65559,
+ mStatus_BadSig = -65560, // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures
+ mStatus_BadKey = -65561,
+ mStatus_TransientErr = -65562, // transient failures, e.g. sending packets shortly after a network transition or wake from sleep
+ mStatus_ServiceNotRunning = -65563, // Background daemon not running
+ mStatus_NATPortMappingUnsupported = -65564, // No NAT or if the NAT doesn't support NAT-PMP or UPnP
+ mStatus_NATPortMappingDisabled = -65565, // NAT supports NAT-PMP or UPnP but it's disabled by the administrator
+ // -65566 to -65786 currently unused; available for allocation
// tcp connection status
mStatus_ConnPending = -65787,
mStatus_GrowCache = -65790,
mStatus_ConfigChanged = -65791,
mStatus_MemFree = -65792 // Last value: 0xFFFE FF00
-
// mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS
};
#define MAX_ESCAPED_DOMAIN_LABEL 254
#define MAX_ESCAPED_DOMAIN_NAME 1005
+// MAX_REVERSE_MAPPING_NAME
+// For IPv4: "123.123.123.123.in-addr.arpa." 30 bytes including terminating NUL
+// For IPv6: "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa." 74 bytes including terminating NUL
+
+#define MAX_REVERSE_MAPPING_NAME_V4 30
+#define MAX_REVERSE_MAPPING_NAME_V6 74
+#define MAX_REVERSE_MAPPING_NAME 74
+
// Most records have a TTL of 75 minutes, so that their 80% cache-renewal query occurs once per hour.
// For records containing a hostname (in the name on the left, or in the rdata on the right),
// like A, AAAA, reverse-mapping PTR, and SRV, we use a two-minute TTL by default, because we don't want
// them to hang around for too long in the cache if the host in question crashes or otherwise goes away.
-// Wide-area service discovery records have a very short TTL to avoid poluting intermediate caches with
-// dynamic records. When discovered via Long Lived Queries (with change notifications), resource record
-// TTLs can be safely ignored.
-
+
#define kStandardTTL (3600UL * 100 / 80)
#define kHostNameTTL 120UL
-#define kWideAreaTTL 3
#define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL)
kDNSRecordTypePacketAns = 0xC0, // Received in the Answer Section of a DNS Response
kDNSRecordTypePacketAnsUnique = 0xD0, // Received in the Answer Section of a DNS Response with kDNSClass_UniqueRRSet set
- kDNSRecordTypePacketAnsMask = 0x40, // True for PacketAns and PacketAnsUnique
+ kDNSRecordTypePacketNegative = 0xF0, // Pseudo-RR generated to cache non-existence results like NXDomain
+
kDNSRecordTypePacketUniqueMask = 0x10 // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique
};
typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;
typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX;
+typedef packedstruct { domainname mbox; domainname txt; } rdataRP;
+typedef packedstruct { mDNSu16 preference; domainname map822; domainname mapx400; } rdataPX;
+
typedef packedstruct
{
domainname mname;
typedef packedstruct
{
- mDNSu16 vers;
- mDNSu16 llqOp;
- mDNSu16 err;
- mDNSu8 id[8];
- mDNSu32 lease;
+ mDNSu16 vers;
+ mDNSu16 llqOp;
+ mDNSu16 err; // Or UDP reply port, in setup request
+ mDNSOpaque64 id;
+ mDNSu32 llqlease;
} LLQOptData;
+// Windows adds pad bytes to sizeof(LLQOptData).
+// Use this macro when setting length fields or validating option rdata from off the wire.
+// Use sizeof(LLQOptData) when dealing with structures (e.g. memcpy).
+// Never memcpy between on-the-wire representation and a structure.
+
#define LLQ_OPTLEN ((3 * sizeof(mDNSu16)) + 8 + sizeof(mDNSu32))
-// Windows adds pad bytes to sizeof(LLQOptData). Use this macro when setting length fields or validating option rdata from
-// off the wire. Use sizeof(LLQOptData) when dealing with structures (e.g. memcpy). Never memcpy between on-the-wire
-// representation and a structure
-
-// NOTE: rdataOpt format may be repeated an arbitrary number of times in a single resource record
+
+// NOTE: rdataOPT format may be repeated an arbitrary number of times in a single resource record
typedef packedstruct
{
mDNSu16 opt;
mDNSu16 optlen;
- union { LLQOptData llq; mDNSu32 lease; } OptData;
- } rdataOpt;
+ union { LLQOptData llq; mDNSu32 updatelease; } OptData;
+ } rdataOPT;
-// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record
+// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record (6 + 256 bytes)
// MaximumRDSize is 8K the absolute maximum we support (at least for now)
#define StandardAuthRDSize 264
#define MaximumRDSize 8192
{
mDNSu8 data[StandardAuthRDSize];
mDNSv4Addr ipv4; // For 'A' record
+ domainname name; // For PTR, NS, CNAME, DNAME
+ rdataSOA soa;
+ UTF8str255 txt;
+ rdataMX mx;
+ rdataRP rp;
+ rdataPX px;
mDNSv6Addr ipv6; // For 'AAAA' record
- domainname name; // For PTR, NS, and CNAME records
- UTF8str255 txt; // For TXT record
- rdataSRV srv; // For SRV record
- rdataMX mx; // For MX record
- rdataSOA soa; // For SOA record
- rdataOpt opt; // For eDNS0 opt record
+ rdataSRV srv;
+ rdataOPT opt; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together
} RDataBody;
typedef struct
typedef struct CacheRecord_struct CacheRecord;
typedef struct CacheGroup_struct CacheGroup;
typedef struct DNSQuestion_struct DNSQuestion;
+typedef struct ZoneData_struct ZoneData;
typedef struct mDNS_struct mDNS;
typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
typedef struct NATTraversalInfo_struct NATTraversalInfo;
// The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely.
typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData);
+// ***************************************************************************
+#if 0
+#pragma mark - NAT Traversal structures and constants
+#endif
+
+#define NATMAP_MAX_RETRY_INTERVAL ((mDNSPlatformOneSecond * 60) * 15) // Max retry interval is 15 minutes
+#define NATMAP_MIN_RETRY_INTERVAL (mDNSPlatformOneSecond * 2) // Min retry interval is 2 seconds
+#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4) // start at 250ms w/ exponential decay
+#define NATMAP_DEFAULT_LEASE (60 * 60) // lease life in seconds
+#define NATMAP_VERS 0
+
+// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets
+// The actual definition of these structures in the in the appropriate platform support code
+typedef struct TCPSocket_struct TCPSocket;
+typedef struct UDPSocket_struct UDPSocket;
+
+typedef enum
+ {
+ NATOp_AddrRequest = 0,
+ NATOp_MapUDP = 1,
+ NATOp_MapTCP = 2,
+
+ NATOp_AddrResponse = 0x80 | 0,
+ NATOp_MapUDPResponse = 0x80 | 1,
+ NATOp_MapTCPResponse = 0x80 | 2,
+ } NATOp_t;
+
+enum
+ {
+ NATErr_None = 0,
+ NATErr_Vers = 1,
+ NATErr_Refused = 2,
+ NATErr_NetFail = 3,
+ NATErr_Res = 4,
+ NATErr_Opcode = 5
+ };
+
+typedef mDNSu16 NATErr_t;
+
+typedef packedstruct
+ {
+ mDNSu8 vers;
+ mDNSu8 opcode;
+ } NATAddrRequest;
+
+typedef packedstruct
+ {
+ mDNSu8 vers;
+ mDNSu8 opcode;
+ mDNSu16 err;
+ mDNSu32 upseconds; // Time since last NAT engine reboot, in seconds
+ mDNSv4Addr ExtAddr;
+ } NATAddrReply;
+
+typedef packedstruct
+ {
+ mDNSu8 vers;
+ mDNSu8 opcode;
+ mDNSOpaque16 unused;
+ mDNSIPPort intport;
+ mDNSIPPort extport;
+ mDNSu32 NATReq_lease;
+ } NATPortMapRequest;
+
+typedef packedstruct
+ {
+ mDNSu8 vers;
+ mDNSu8 opcode;
+ mDNSu16 err;
+ mDNSu32 upseconds; // Time since last NAT engine reboot, in seconds
+ mDNSIPPort intport;
+ mDNSIPPort extport;
+ mDNSu32 NATRep_lease;
+ } NATPortMapReply;
+
+typedef enum
+ {
+ LNTDiscoveryOp = 1,
+ LNTExternalAddrOp = 2,
+ LNTPortMapOp = 3,
+ LNTPortMapDeleteOp = 4
+ } LNTOp_t;
+
+#define LNT_MAXBUFSIZE 4096
+typedef struct tcpLNTInfo_struct tcpLNTInfo;
+struct tcpLNTInfo_struct
+ {
+ tcpLNTInfo *next;
+ mDNS *m;
+ NATTraversalInfo *parentNATInfo; // pointer back to the parent NATTraversalInfo
+ TCPSocket *sock;
+ LNTOp_t op; // operation performed using this connection
+ mDNSAddr Address; // router address
+ mDNSIPPort Port; // router port
+ mDNSs8 *Request; // xml request to router
+ int requestLen;
+ mDNSs8 *Reply; // xml reply from router
+ int replyLen;
+ unsigned long nread; // number of bytes read so far
+ int retries; // number of times we've tried to do this port mapping
+ };
+
+typedef void (*NATTraversalClientCallback)(mDNS *m, NATTraversalInfo *n);
+
+// if m->timenow < ExpiryTime then we have an active mapping, and we'll renew halfway to expiry
+// if m->timenow >= ExpiryTime then our mapping has expired, and we're trying to create one
+
+struct NATTraversalInfo_struct
+ {
+ // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+ NATTraversalInfo *next;
+
+ mDNSs32 ExpiryTime; // Time this mapping expires, or zero if no mapping
+ mDNSs32 retryInterval; // Current interval, between last packet we sent and the next one
+ mDNSs32 retryPortMap; // If Protocol is nonzero, time to send our next mapping packet
+ mStatus NewResult; // New error code; will be copied to Result just prior to invoking callback
+
+#ifdef _LEGACY_NAT_TRAVERSAL_
+ tcpLNTInfo tcpInfo; // Legacy NAT traversal (UPnP) TCP connection
+#endif
+
+ // Result fields: When the callback is invoked these fields contain the answers the client is looking for
+ // When the callback is invoked ExternalPort is *usually* set to be the same the same as RequestedPort, except:
+ // (a) When we're behind a NAT gateway with port mapping disabled, ExternalPort is reported as zero to
+ // indicate that we don't currently have a working mapping (but RequestedPort retains the external port
+ // we'd like to get, the next time we meet an accomodating NAT gateway willing to give us one).
+ // (b) When we have a routable non-RFC1918 address, we don't *need* a port mapping, so ExternalPort
+ // is reported as the same as our InternalPort, since that is effectively our externally-visible port too.
+ // Again, RequestedPort retains the external port we'd like to get the next time we find ourself behind a NAT gateway.
+ // To improve stability of port mappings, RequestedPort is updated any time we get a successful
+ // mapping response from the NAT-PMP or UPnP gateway. For example, if we ask for port 80, and
+ // get assigned port 81, then thereafter we'll contine asking for port 81.
+ mDNSInterfaceID InterfaceID;
+ mDNSv4Addr ExternalAddress;
+ mDNSIPPort ExternalPort;
+ mDNSu32 Lifetime;
+ mStatus Result;
+
+ // Client API fields: The client must set up these fields *before* making any NAT traversal API calls
+ mDNSu8 Protocol; // NATOp_MapUDP or NATOp_MapTCP, or zero if just requesting the external IP address
+ mDNSIPPort IntPort; // Client's internal port number (doesn't change)
+ mDNSIPPort RequestedPort; // Requested public port mapping; may be updated with actual value assigned by gateway
+ mDNSu32 NATLease; // Requested lifetime in seconds (doesn't change)
+ NATTraversalClientCallback clientCallback;
+ void *clientContext;
+ };
+
typedef struct
{
- mDNSu8 RecordType; // See enum above
- mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface
+ mDNSu8 RecordType; // See enum above
+ mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface
// For records received off the wire, InterfaceID is *always* set to the receiving interface
// For our authoritative records, InterfaceID is usually zero, except for those few records
// that are interface-specific (e.g. address records, especially linklocal addresses)
- domainname *name;
- mDNSu16 rrtype;
- mDNSu16 rrclass;
- mDNSu32 rroriginalttl; // In seconds
- mDNSu16 rdlength; // Size of the raw rdata, in bytes
- mDNSu16 rdestimate; // Upper bound on size of rdata after name compression
- mDNSu32 namehash; // Name-based (i.e. case-insensitive) hash of name
- mDNSu32 rdatahash; // For rdata containing domain name (e.g. PTR, SRV, CNAME etc.), case-insensitive name hash
+ const domainname *name;
+ mDNSu16 rrtype;
+ mDNSu16 rrclass;
+ mDNSu32 rroriginalttl; // In seconds
+ mDNSu16 rdlength; // Size of the raw rdata, in bytes, in the on-the-wire format
+ // (in-memory storage may be larger, for structures containing 'holes', like SOA)
+ mDNSu16 rdestimate; // Upper bound on size of rdata after name compression
+ mDNSu32 namehash; // Name-based (i.e. case-insensitive) hash of name
+ mDNSu32 rdatahash; // For rdata containing domain name (e.g. PTR, SRV, CNAME etc.), case-insensitive name hash
// else, for all other rdata, 32-bit hash of the raw rdata
// Note: This requirement is important. Various routines like AddAdditionalsToResponseList(),
// ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see
RData *rdata; // Pointer to storage for this rdata
} ResourceRecord;
-// Unless otherwise noted, states may apply to either independent record registrations or service registrations
+// Unless otherwise noted, states may apply to either independent record registrations or service registrations
typedef enum
{
+ regState_Zero = 0,
regState_FetchingZoneData = 1, // getting info - update not sent
regState_Pending = 2, // update sent, reply not received
regState_Registered = 3, // update sent, reply received
regState_DeregPending = 4, // dereg sent, reply not received
regState_DeregDeferred = 5, // dereg requested while in Pending state - send dereg AFTER registration is confirmed
- regState_Cancelled = 6, // update not sent, reg. cancelled by client
regState_Unregistered = 8, // not in any list
regState_Refresh = 9, // outstanding refresh (or target change) message
- regState_NATMap = 10, // establishing NAT port mapping or learning public address
+ regState_NATMap = 10, // establishing NAT port mapping (service registrations only)
regState_UpdatePending = 11, // update in flight as result of mDNS_Update call
regState_NoTarget = 12, // service registration pending registration of hostname (ServiceRegistrations only)
- regState_ExtraQueued = 13, // extra record to be registered upon completion of service registration (RecordRegistrations only)
+ regState_ExtraQueued = 13, // extra record to be registered upon completion of service registration (RecordRegistrations only)
regState_NATError = 14 // unable to complete NAT traversal
- } regState_t;
+ } regState_t;
-// context for both ServiceRecordSet and individual AuthRec structs
-typedef struct
+enum
{
- // registration/lease state
- regState_t state;
- mDNSBool lease; // dynamic update contains (should contain) lease option
- mDNSs32 expire; // expiration of lease (-1 for static)
- mDNSBool TestForSelfConflict; // on name conflict, check if we're just seeing our own orphaned records
-
- // identifier to match update request and response
- mDNSOpaque16 id;
-
- // server info
- domainname zone; // the zone that is updated
- mDNSAddr ns; // primary name server for the record's zone !!!KRS not technically correct to cache longer than TTL
- mDNSIPPort port; // port on which server accepts dynamic updates
-
- // NAT traversal context
- NATTraversalInfo *NATinfo; // may be NULL
-
- // state for deferred operations
- mDNSBool ClientCallbackDeferred; // invoke client callback on completion of pending operation(s)
- mStatus DeferredStatus; // status to deliver when above flag is set
- mDNSBool SRVUpdateDeferred; // do we need to change target or port once current operation completes?
- mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed
-
- // uDNS_UpdateRecord support fields
- RData *OrigRData; mDNSu16 OrigRDLen; // previously registered, being deleted
- RData *InFlightRData; mDNSu16 InFlightRDLen; // currently being registered
- RData *QueuedRData; mDNSu16 QueuedRDLen; // if the client call Update while an update is in flight, we must finish the
- // pending operation (re-transmitting if necessary) THEN register the queued update
- mDNSRecordUpdateCallback *UpdateRDCallback; // client callback to free old rdata
- } uDNS_RegInfo;
+ Target_Manual = 0,
+ Target_AutoHost = 1,
+ Target_AutoHostAndNATMAP = 2
+ };
struct AuthRecord_struct
{
AuthRecord *next; // Next in list; first element of structure for efficiency reasons
// Field Group 1: Common ResourceRecord fields
ResourceRecord resrec;
- uDNS_RegInfo uDNS_info;
// Field Group 2: Persistent metadata for Authoritative Records
- AuthRecord *Additional1; // Recommended additional record to include in response
- AuthRecord *Additional2; // Another additional
+ AuthRecord *Additional1; // Recommended additional record to include in response (e.g. SRV for PTR record)
+ AuthRecord *Additional2; // Another additional (e.g. TXT for record)
AuthRecord *DependentOn; // This record depends on another for its uniqueness checking
AuthRecord *RRSet; // This unique record is part of an RRSet
mDNSRecordCallback *RecordCallback; // Callback function to call for state changes, and to free memory asynchronously on deregistration
void *RecordContext; // Context parameter for the callback function
- mDNSu8 HostTarget; // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
+ mDNSu8 AutoTarget; // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
mDNSu8 AllowRemoteQuery; // Set if we allow hosts not on the local link to query this record
mDNSu8 ForceMCast; // Set by client to advertise solely via multicast, even for apparently unicast names
const mDNSu8 *NR_AnswerTo; // Set if this record was selected by virtue of being a direct answer to a question
AuthRecord *NR_AdditionalTo; // Set if this record was selected by virtue of being additional to another
mDNSs32 ThisAPInterval; // In platform time units: Current interval for announce/probe
- mDNSs32 AnnounceUntil; // In platform time units: Creation time + TTL
mDNSs32 LastAPTime; // In platform time units: Last time we sent announcement/probe
mDNSs32 LastMCTime; // Last time we multicast this record (used to guard against packet-storm attacks)
mDNSInterfaceID LastMCInterface; // Interface this record was multicast on at the time LastMCTime was recorded
mDNSs32 NextUpdateCredit; // Time next token is added to bucket
mDNSs32 UpdateBlocked; // Set if update delaying is in effect
+ // Field Group 4: Transient uDNS state for Authoritative Records
+ regState_t state; // Maybe combine this with resrec.RecordType state? Right now it's ambiguous and confusing.
+ // e.g. rr->resrec.RecordType can be kDNSRecordTypeUnregistered,
+ // and rr->state can be regState_Unregistered
+ // What if we find one of those statements is true and the other false? What does that mean?
+ mDNSBool uselease; // dynamic update contains (should contain) lease option
+ mDNSs32 expire; // expiration of lease (-1 for static)
+ mDNSBool Private; // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping
+ mDNSOpaque16 id; // identifier to match update request and response
+ domainname zone; // the zone that is updated
+ mDNSAddr UpdateServer; // DNS server that handles updates for this zone
+ mDNSIPPort UpdatePort; // port on which server accepts dynamic updates
+ // !!!KRS not technically correct to cache longer than TTL
+ // SDC Perhaps should keep a reference to the relevant SRV record in the cache?
+ ZoneData *nta;
+ struct tcpInfo_t *tcp;
+
+ // uDNS_UpdateRecord support fields
+ // Do we really need all these in *addition* to NewRData and newrdlength above?
+ RData *OrigRData;
+ mDNSu16 OrigRDLen; // previously registered, being deleted
+ RData *InFlightRData;
+ mDNSu16 InFlightRDLen; // currently being registered
+ RData *QueuedRData; // if the client call Update while an update is in flight, we must finish the
+ mDNSu16 QueuedRDLen; // pending operation (re-transmitting if necessary) THEN register the queued update
+
+ // Field Group 5: Large data objects go at the end
domainname namestorage;
RData rdatastorage; // Normally the storage is right here, except for oversized records
// rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes
domainname namestorage; // Needs to go *after* the extra rdata bytes
} LargeCacheRecord;
-typedef struct uDNS_HostnameInfo
+typedef struct HostnameInfo
{
- struct uDNS_HostnameInfo *next;
- domainname fqdn;
- AuthRecord *arv4; // registered IPv4 address record
- AuthRecord *arv6; // registered IPv6 address record
+ struct HostnameInfo *next;
+ NATTraversalInfo natinfo;
+ domainname fqdn;
+ AuthRecord arv4; // registered IPv4 address record
+ AuthRecord arv6; // registered IPv6 address record
mDNSRecordCallback *StatusCallback; // callback to deliver success or error code to client layer
const void *StatusContext; // Client Context
- } uDNS_HostnameInfo;
+ } HostnameInfo;
enum
- {
- DNSServer_Untested = 0,
- DNSServer_Failed = 1,
- DNSServer_Passed = 2
- };
+ {
+ DNSServer_Untested = 0,
+ DNSServer_Passed = 1,
+ DNSServer_Failed = 2,
+ DNSServer_Disabled = 3
+ };
typedef struct DNSServer
{
- struct DNSServer *next;
- mDNSAddr addr;
- mDNSBool del; // Set when we're planning to delete this from the list
- mDNSu32 teststate; // Have we sent bug-detection query to this server?
- domainname domain; // name->server matching for "split dns"
+ struct DNSServer *next;
+ mDNSInterfaceID interface; // For specialized uses; we can have DNS servers reachable over specific interfaces
+ mDNSAddr addr;
+ mDNSIPPort port;
+ mDNSBool del; // Set when we're planning to delete this from the list
+ mDNSu32 teststate; // Have we sent bug-detection query to this server?
+ mDNSs32 lasttest; // Time we sent last bug-detection query to this server
+ domainname domain; // name->server matching for "split dns"
} DNSServer;
typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
struct ExtraResourceRecord_struct
{
ExtraResourceRecord *next;
- mDNSu32 ClientID; // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records
+ mDNSu32 ClientID; // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records
AuthRecord r;
// Note: Add any additional fields *before* the AuthRecord in this structure, not at the end.
// In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate
// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
typedef struct ServiceRecordSet_struct ServiceRecordSet;
typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
+
+// A ServiceRecordSet is basically a convenience structure to group together
+// the PTR/SRV/TXT records that make up a standard service registration
+// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above
+// It also contains:
+// * the "_services" PTR record for service enumeration
+// * the optional target host name (for proxy registrations)
+// * the optional list of SubType PTR records
+// * the optional list of additional records attached to the service set (e.g. iChat pictures)
+//
+// ... and a bunch of stuff related to uDNS, some of which could be simplified or eliminated
+
struct ServiceRecordSet_struct
{
- // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
+ // These internal state fields are used internally by mDNSCore; the client layer needn't be concerned with them.
// No fields need to be set up by the client prior to calling mDNS_RegisterService();
// all required data is passed as parameters to that function.
- ServiceRecordSet *next;
- uDNS_RegInfo uDNS_info;
+
+ // Begin uDNS info ****************
+ // Hopefully much of this stuff can be simplified or eliminated
+
+ // NOTE: The current uDNS code keeps an explicit list of registered services, and handles them
+ // differently to how individual records are treated (this is probably a mistake). What this means is
+ // that ServiceRecordSets for uDNS are kept in a linked list, whereas ServiceRecordSets for mDNS exist
+ // just as a convenient placeholder to group the component records together and are not kept on any list.
+ ServiceRecordSet *uDNS_next;
+ regState_t state;
+ mDNSBool srs_uselease; // dynamic update contains (should contain) lease option
+ mDNSs32 expire; // expiration of lease (-1 for static)
+ mDNSBool TestForSelfConflict; // on name conflict, check if we're just seeing our own orphaned records
+ mDNSBool Private; // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping
+ ZoneData *nta;
+ mDNSOpaque16 id;
+ domainname zone; // the zone that is updated
+ mDNSAddr ns; // primary name server for the record's zone !!!KRS not technically correct to cache longer than TTL
+ mDNSIPPort SRSUpdatePort; // port on which server accepts dynamic updates
+ NATTraversalInfo NATinfo; // may be NULL
+ mDNSBool ClientCallbackDeferred; // invoke client callback on completion of pending operation(s)
+ mStatus DeferredStatus; // status to deliver when above flag is set
+ mDNSBool SRVUpdateDeferred; // do we need to change target or port once current operation completes?
+ mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed
+ struct tcpInfo_t *tcp;
+
+ // End uDNS info ****************
+
mDNSServiceCallback *ServiceCallback;
void *ServiceContext;
+ mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict
+
ExtraResourceRecord *Extras; // Optional list of extra AuthRecords attached to this service registration
mDNSu32 NumSubTypes;
AuthRecord *SubTypes;
- mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict
- domainname Host; // Set if this service record does not use the standard target host name
AuthRecord RR_ADV; // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local.
AuthRecord RR_PTR; // e.g. _printer._tcp.local. PTR Name._printer._tcp.local.
AuthRecord RR_SRV; // e.g. Name._printer._tcp.local. SRV 0 0 port target
LLQ_SecondaryRequest = 3,
LLQ_Refresh = 4,
LLQ_Retry = 5,
- LLQ_Established = 6,
- LLQ_Suspended = 7,
+ LLQ_Established = 6,
+ LLQ_Suspended = 7,
LLQ_SuspendDeferred = 8, // suspend once we get zone info
LLQ_SuspendedPoll = 9, // suspended from polling state
- LLQ_NatMapWait = 10,
-
+ LLQ_NatMapWaitUDP = 10,
+
// Established/error states
LLQ_Static = 16,
LLQ_Poll = 17,
LLQ_Cancelled = 19
} LLQ_State;
-typedef struct
- {
- LLQ_State state;
- mDNSAddr servAddr;
- mDNSIPPort servPort;
- DNSQuestion *question;
- mDNSu32 origLease; // seconds (relative)
- mDNSs32 retry; // ticks (absolute)
- mDNSs32 expire; // ticks (absolute)
- mDNSs16 ntries;
- mDNSu8 id[8];
- mDNSBool deriveRemovesOnResume;
- mDNSBool NATMap; // does this LLQ use the global LLQ NAT mapping?
- } LLQ_Info;
-
// LLQ constants
#define kDNSOpt_LLQ 1
#define kDNSOpt_Lease 2
#define kLLQOp_Refresh 2
#define kLLQOp_Event 3
-#define LLQ_OPT_RDLEN ((2 * sizeof(mDNSu16)) + LLQ_OPTLEN)
-#define LEASE_OPT_RDLEN (2 * sizeof(mDNSu16)) + sizeof(mDNSs32)
+#define LLQ_OPT_RDLEN ((2 * sizeof(mDNSu16)) + LLQ_OPTLEN )
+#define LEASE_OPT_RDLEN ((2 * sizeof(mDNSu16)) + sizeof(mDNSs32))
// LLQ Errror Codes
enum
LLQErr_UnknownErr = 6
};
-typedef void (*InternalResponseHndlr)(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *internalContext);
-typedef struct
+enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
+
+#define HMAC_LEN 64
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+#define MD5_LEN 16
+
+#define AutoTunnelUnregistered(X) ( \
+ (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
+ (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
+ (X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered )
+
+// Internal data structure to maintain authentication information
+typedef struct DomainAuthInfo
{
- mDNSOpaque16 id;
- mDNSBool internal;
- InternalResponseHndlr responseCallback; // NULL if internal field is false
- LLQ_Info *llq; // NULL for 1-shot queries
- mDNSBool Answered; // have we received an answer (including NXDOMAIN) for this question?
- CacheRecord *knownAnswers;
- mDNSs32 RestartTime; // Mark when we restart a suspended query
- void *context;
- } uDNS_QuestionInfo;
+ struct DomainAuthInfo *next;
+ mDNSs32 deltime; // If we're planning to delete this DomainAuthInfo, the time we want it deleted
+ mDNSBool AutoTunnel;
+ AuthRecord AutoTunnelHostRecord; // User-visible hostname; used as SRV target for AutoTunnel services
+ AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
+ AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint
+ AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
+ NATTraversalInfo AutoTunnelNAT;
+ domainname domain;
+ domainname keyname;
+ char b64keydata[32];
+ mDNSu8 keydata_ipad[HMAC_LEN]; // padded key for inner hash rounds
+ mDNSu8 keydata_opad[HMAC_LEN]; // padded key for outer hash rounds
+ } DomainAuthInfo;
// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute()
-typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+typedef enum { QC_rmv = 0, QC_add = 1, QC_addnocache = 2 } QC_result;
+typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
struct DNSQuestion_struct
{
// Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
mDNSs32 ThisQInterval; // LastQTime + ThisQInterval is the next scheduled transmission of this Q
// ThisQInterval > 0 for an active question;
// ThisQInterval = 0 for a suspended question that's still in the list
- // ThisQInterval = -1 for a cancelled question that's been removed from the list
+ // ThisQInterval = -1 for a cancelled question (should not still be in list)
+ mDNSs32 ExpectUnicastResp;// Set when we send a query with the kDNSQClass_UnicastResponse bit set
mDNSs32 LastAnswerPktNum; // The sequence number of the last response packet containing an answer to this Q
mDNSu32 RecentAnswerPkts; // Number of answers since the last time we sent this query
mDNSu32 CurrentAnswers; // Number of records currently in the cache that answer this question
mDNSu32 LargeAnswers; // Number of answers with rdata > 1024 bytes
mDNSu32 UniqueAnswers; // Number of answers received with kDNSClass_UniqueRRSet bit set
+ mDNSInterfaceID FlappingInterface1;// Set when an interface goes away, to flag if remove events are delivered for this Q
+ mDNSInterfaceID FlappingInterface2;// Set when an interface goes away, to flag if remove events are delivered for this Q
+ DomainAuthInfo *AuthInfo; // Non-NULL if query is currently being done using Private DNS
DNSQuestion *DuplicateOf;
DNSQuestion *NextInDQList;
DupSuppressInfo DupSuppress[DupSuppressInfoSize];
mDNSBool SendOnAll; // Set if we're sending this question on all active interfaces
mDNSu32 RequestUnicast; // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set
mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces
- uDNS_QuestionInfo uDNS_info;
+ mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done
+
+ // Wide Area fields. These are used internally by the uDNS core
+ DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise)
+
+ ZoneData *nta; // Used for getting zone data for private or LLQ query
+ mDNSAddr servAddr; // Address and port learned from _dns-llq, _dns-llq-tls or _dns-query-tls SRV query
+ mDNSIPPort servPort;
+ struct tcpInfo_t *tcp;
+ mDNSu8 NoAnswer; // Set if we want to suppress answers until tunnel setup has completed
+
+ // LLQ-specific fields. These fields are only meaningful when LongLived flag is set
+ LLQ_State state;
+ NATTraversalInfo NATInfoUDP;
+ mDNSIPPort eventPort; // This is non-zero if this is a private LLQ. If we're behind NAT, it's the external UDP port.
+ mDNSu32 origLease; // seconds (relative)
+ mDNSs32 expire; // ticks (absolute)
+ mDNSs16 ntries;
+ mDNSOpaque64 id;
// Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
mDNSInterfaceID InterfaceID; // Non-zero if you want to issue queries only on a single specific IP interface
mDNSBool LongLived; // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer.
mDNSBool ExpectUnique; // Set by client if it's expecting unique RR(s) for this question, not shared RRs
mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names
+ mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
mDNSQuestionCallback *QuestionCallback;
void *QuestionContext;
};
void *ServiceInfoQueryContext;
};
-// ***************************************************************************
-#if 0
-#pragma mark - NAT Traversal structures and constants
-#endif
-
-#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4) // start at 250ms w/ exponential decay
-#define NATMAP_MAX_RETRY mDNSPlatformOneSecond // back off to once per second
-#define NATMAP_MAX_TRIES 3 // for max 3 tries
-#define NATMAP_DEFAULT_LEASE (60 * 60) // lease life in seconds
-#define NATMAP_VERS 0
-#define NATMAP_PORT 5351
-#define NATMAP_RESPONSE_MASK 0x80
-
-typedef enum
- {
- NATOp_AddrRequest = 0,
- NATOp_MapUDP = 1,
- NATOp_MapTCP = 2
- } NATOp_t;
+typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ } ZoneService;
-enum
- {
- NATErr_None = 0,
- NATErr_Vers = 1,
- NATErr_Refused = 2,
- NATErr_NetFail = 3,
- NATErr_Res = 4,
- NATErr_Opcode = 5
- };
+typedef void ZoneDataCallback(mDNS *const m, mStatus err, const ZoneData *result);
-typedef mDNSu16 NATErr_t;
-
-typedef enum
+struct ZoneData_struct
{
- NATState_Init = 0,
- NATState_Request = 1,
- NATState_Established = 2,
- NATState_Legacy = 3,
- NATState_Error = 4,
- NATState_Refresh = 5,
- NATState_Deleted = 6
- } NATState_t;
-// Note: we have no explicit "cancelled" state, where a service/interface is deregistered while we
- // have an outstanding NAT request. This is conveyed by the "reg" pointer being set to NULL
+ domainname ChildName; // Name for which we're trying to find the responsible server
+ ZoneService ZoneService; // Which service we're seeking for this zone (update, query, or LLQ)
+ domainname *CurrentSOA; // Points to somewhere within ChildName
+ domainname ZoneName; // Discovered result: Left-hand-side of SOA record
+ mDNSu16 ZoneClass; // Discovered result: DNS Class from SOA record
+ domainname Host; // Discovered result: Target host from SRV record
+ mDNSIPPort Port; // Discovered result: Update port, query port, or LLQ port from SRV record
+ mDNSAddr Addr; // Discovered result: Address of Target host from SRV record
+ mDNSBool ZonePrivate; // Discovered result: Does zone require encrypted queries?
+ ZoneDataCallback *ZoneDataCallback; // Caller-specified function to be called upon completion
+ void *ZoneDataContext;
+ DNSQuestion question; // Storage for any active question
+ };
-typedef packedstruct
- {
- mDNSu8 vers;
- mDNSu8 opcode;
- } NATAddrRequest;
-
-typedef packedstruct
- {
- mDNSu8 vers;
- mDNSu8 opcode;
- mDNSOpaque16 err;
- mDNSOpaque32 uptime;
- mDNSv4Addr PubAddr;
- } NATAddrReply;
+extern ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *callbackInfo);
+extern void CancelGetZoneData(mDNS *const m, ZoneData *nta);
-typedef packedstruct
- {
- mDNSu8 vers;
- mDNSu8 opcode;
- mDNSOpaque16 unused;
- mDNSIPPort priv;
- mDNSIPPort pub;
- mDNSOpaque32 lease;
- } NATPortMapRequest;
-
-typedef packedstruct
+typedef struct DNameListElem
{
- mDNSu8 vers;
- mDNSu8 opcode;
- mDNSOpaque16 err;
- mDNSOpaque32 uptime;
- mDNSIPPort priv;
- mDNSIPPort pub;
- mDNSOpaque32 lease;
- } NATPortMapReply;
-
-// Pass NULL for pkt on error (including timeout)
-typedef mDNSBool (*NATResponseHndlr)(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len);
+ struct DNameListElem *next;
+ mDNSu32 uid;
+ domainname name;
+ } DNameListElem;
-struct NATTraversalInfo_struct
+#if APPLE_OSX_mDNSResponder
+typedef struct ClientTunnel
{
- NATOp_t op;
- NATResponseHndlr ReceiveResponse;
- union { AuthRecord *RecordRegistration; ServiceRecordSet *ServiceRegistration; } reg;
- mDNSAddr Router;
- mDNSIPPort PublicPort;
- union { NATAddrRequest AddrReq; NATPortMapRequest PortReq; } request;
- mDNSs32 retry; // absolute time when we retry
- mDNSs32 RetryInterval; // delta between time sent and retry
- int ntries;
- NATState_t state;
- NATTraversalInfo *next;
- };
+ struct ClientTunnel *next;
+ domainname dstname;
+ mDNSBool markedForDeletion;
+ mDNSv6Addr loc_inner;
+ mDNSv4Addr loc_outer;
+ mDNSv6Addr rmt_inner;
+ mDNSv4Addr rmt_outer;
+ mDNSIPPort rmt_outer_port;
+ char b64keydata[32];
+ DNSQuestion q;
+ } ClientTunnel;
+#endif
// ***************************************************************************
#if 0
mDNS_KnownBug_PhantomInterfaces = 1
};
-typedef struct
- {
- mDNSs32 nextevent;
- DNSQuestion *ActiveQueries; //!!!KRS this should be a hashtable (hash on messageID)
- DNSQuestion *CurrentQuery; // pointer to ActiveQueries list being examined in a loop. Functions that remove
- // elements from the ActiveQueries list must update this pointer (if non-NULL) as necessary.
- //!!!KRS do the same for registration lists
- ServiceRecordSet *ServiceRegistrations;
- AuthRecord *RecordRegistrations;
- NATTraversalInfo *NATTraversals;
- mDNSu16 NextMessageID;
- DNSServer *Servers; // list of DNS servers
- mDNSAddr Router;
- mDNSAddr AdvertisedV4; // IPv4 address pointed to by hostname
- mDNSAddr MappedV4; // Cache of public address if PrimaryIP is behind a NAT
- mDNSAddr AdvertisedV6; // IPv6 address pointed to by hostname
- NATTraversalInfo *LLQNatInfo; // Nat port mapping to receive LLQ events
- domainname ServiceRegDomain; // (going away w/ multi-user support)
- struct uDNS_AuthInfo *AuthInfoList; // list of domains requiring authentication for updates.
- uDNS_HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata
- DNSQuestion ReverseMap; // Reverse-map query to find static hostname for service target
- mDNSBool ReverseMapActive; // Is above query active?
- domainname StaticHostname; // Current answer to reverse-map query (above)
- mDNSBool DelaySRVUpdate; // Delay SRV target/port update to avoid "flap"
- mDNSs32 NextSRVUpdate; // Time to perform delayed update
- } uDNS_GlobalInfo;
-
struct mDNS_struct
{
// Internal state fields. These hold the main internal state of mDNSCore;
mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified
mDNSu8 lock_Questions;
mDNSu8 lock_Records;
- char MsgBuffer[80]; // Temp storage used while building error log messages
+ #define MaxMsg 120
+ char MsgBuffer[MaxMsg]; // Temp storage used while building error log messages
// Task Scheduling variables
mDNSs32 timenow_adjust; // Correction applied if we ever discover time went backwards
mDNSs32 NextScheduledQuery; // Next time to send query in its exponential backoff sequence
mDNSs32 NextScheduledProbe; // Next time to probe for new authoritative record
mDNSs32 NextScheduledResponse; // Next time to send authoritative record(s) in responses
- mDNSs32 ExpectUnicastResponse; // Set when we send a query with the kDNSQClass_UnicastResponse bit set
+ mDNSs32 NextScheduledNATOp; // Next time to send NAT-traversal packets
mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire
+ mDNSu32 RandomReconfirmDelay; // For de-synchronization of reconfirmation queries on the wire
mDNSs32 PktNum; // Unique sequence number assigned to each received packet
mDNSBool SendDeregistrations; // Set if we need to send deregistrations (immediately)
mDNSBool SendImmediateAnswers; // Set if we need to send answers (immediately -- or as soon as SuppressSending clears)
domainname MulticastHostname; // Fully Qualified "dot-local" Host Name, e.g. "Foo.local."
UTF8str255 HIHardware;
UTF8str255 HISoftware;
+ AuthRecord DeviceInfo;
AuthRecord *ResourceRecords;
AuthRecord *DuplicateRecords; // Records currently 'on hold' because they are duplicates of existing records
AuthRecord *NewLocalRecords; // Fresh local-only records not yet delivered to local-only questions
mDNSs32 SuppressProbes;
// unicast-specific data
- uDNS_GlobalInfo uDNS_info;
- mDNSs32 SuppressStdPort53Queries; // Wait before allowing the next standard unicast query to the user's configured DNS server
+ mDNSs32 NextuDNSEvent; // uDNS next event
+ mDNSs32 NextSRVUpdate; // Time to perform delayed update
+ mDNSs32 SuppressStdPort53Queries; // Wait before allowing the next standard unicast query to the user's configured DNS server
+
+ ServiceRecordSet *ServiceRegistrations;
+ mDNSu16 NextMessageID;
+ DNSServer *DNSServers; // list of DNS servers
+
+ mDNSAddr Router;
+ mDNSAddr AdvertisedV4; // IPv4 address pointed to by hostname
+ mDNSAddr AdvertisedV6; // IPv6 address pointed to by hostname
+
+ DomainAuthInfo *AuthInfoList; // list of domains requiring authentication for updates
+
+ DNSQuestion ReverseMap; // Reverse-map query to find static hostname for service target
+ DNSQuestion AutomaticBrowseDomainQ;
+ domainname StaticHostname; // Current answer to reverse-map query
+ domainname FQDN;
+ HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata
+ mDNSv6Addr AutoTunnelHostAddr; // IPv6 address advertised for AutoTunnel services on this machine
+ mDNSBool AutoTunnelHostAddrActive;
+ domainlabel AutoTunnelLabel; // Used to construct hostname for *IPv4* address of tunnel endpoints
+
+ mDNSBool RegisterSearchDomains;
+
+ // NAT traversal fields
+ NATTraversalInfo *NATTraversals;
+ NATTraversalInfo *CurrentNATTraversal;
+ mDNSs32 retryIntervalGetAddr; // delta between time sent and retry
+ mDNSs32 retryGetAddr; // absolute time when we retry
+ mDNSv4Addr ExternalAddress;
+
+ UDPSocket *NATMcastRecvskt; // For receiving NAT-PMP AddrReply multicasts from router on port 5350
+ UDPSocket *NATMcastRecvsk2; // For backwards compatibility, same as above but listening on port 5351
+ mDNSu32 LastNATupseconds; // NAT engine uptime in seconds, from most recent NAT packet
+ mDNSs32 LastNATReplyLocalTime; // Local time in ticks when most recent NAT packet was received
+
+ tcpLNTInfo tcpAddrInfo; // legacy NAT traversal TCP connection info for external address
+ tcpLNTInfo tcpDeviceInfo; // legacy NAT traversal TCP connection info for device info
+ tcpLNTInfo *tcpInfoUnmapList; // list of pending unmap requests
+ mDNSInterfaceID UPnPInterfaceID;
+ mDNSIPPort UPnPRouterPort; // port we send discovery messages to
+ mDNSIPPort UPnPSOAPPort; // port we send SOAP messages to
+ mDNSu8 *UPnPRouterURL; // router's URL string
+ mDNSu8 *UPnPSOAPURL; // router's SOAP control URL string
+ mDNSu8 *UPnPRouterAddressString; // holds both the router's address and port
+ mDNSu8 *UPnPSOAPAddressString; // holds both address and port for SOAP messages
+
+#if APPLE_OSX_mDNSResponder
+ ClientTunnel *TunnelClients;
+#endif
// Fixed storage, to avoid creating large objects on the stack
- DNSMessage imsg; // Incoming message received from wire
- DNSMessage omsg; // Outgoing message we're building
- LargeCacheRecord rec; // Resource Record extracted from received message
+ DNSMessage imsg; // Incoming message received from wire
+ DNSMessage omsg; // Outgoing message we're building
+ LargeCacheRecord rec; // Resource Record extracted from received message
};
-#define FORALL_CACHERECORDS(SLOT,CG,CR) \
- for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++) \
- for((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \
+#define FORALL_CACHERECORDS(SLOT,CG,CR) \
+ for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++) \
+ for ((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \
for ((CR) = (CG)->members; (CR); (CR)=(CR)->next)
// ***************************************************************************
extern const mDNSInterfaceID mDNSInterface_Any; // Zero
extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value
+extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value
-extern const mDNSIPPort UnicastDNSPort;
-extern const mDNSIPPort MulticastDNSPort;
-extern const mDNSv4Addr AllDNSAdminGroup;
-extern const mDNSv4Addr AllDNSLinkGroupv4;
-extern const mDNSv6Addr AllDNSLinkGroupv6;
-extern const mDNSAddr AllDNSLinkGroup_v4;
-extern const mDNSAddr AllDNSLinkGroup_v6;
+extern const mDNSIPPort SSDPPort;
+
+extern const mDNSIPPort UnicastDNSPort;
+extern const mDNSIPPort NATPMPAnnouncementPort;
+extern const mDNSIPPort NATPMPPort;
+extern const mDNSIPPort DNSEXTPort;
+extern const mDNSIPPort MulticastDNSPort;
+extern const mDNSIPPort LoopbackIPCPort;
+
+extern const mDNSIPPort NSIPCPort;
+extern const mDNSIPPort PrivateDNSPort;
+
+extern const mDNSv4Addr AllDNSAdminGroup;
+extern const mDNSAddr AllDNSLinkGroup_v4;
+extern const mDNSAddr AllDNSLinkGroup_v6;
extern const mDNSOpaque16 zeroID;
extern const mDNSOpaque16 QueryFlags;
extern const mDNSOpaque16 UpdateReqFlags;
extern const mDNSOpaque16 UpdateRespFlags;
-#define localdomain (*(const domainname *)"\x5local")
-#define LocalReverseMapomain (*(const domainname *)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa")
-
+extern const mDNSOpaque64 zeroOpaque64;
+
+#define localdomain (*(const domainname *)"\x5" "local")
+#define LocalReverseMapDomain (*(const domainname *)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa")
+#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
+
// ***************************************************************************
#if 0
#pragma mark - Inline functions
#if !defined(mDNSinline)
extern mDNSs32 NonZeroTime(mDNSs32 t);
extern mDNSu16 mDNSVal16(mDNSOpaque16 x);
-extern mDNSu32 mDNSVal32(mDNSOpaque32 x);
extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
-extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v);
#endif
// If we're compiling the particular C file that instantiates our inlines, then we
mDNSinline mDNSs32 NonZeroTime(mDNSs32 t) { if (t) return(t); else return(1); }
mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x) { return((mDNSu16)((mDNSu16)x.b[0] << 8 | (mDNSu16)x.b[1])); }
-mDNSinline mDNSu32 mDNSVal32(mDNSOpaque32 x) { return((mDNSu32)((mDNSu32)x.b[0] << 24 | (mDNSu32)x.b[1] << 16 | (mDNSu32)x.b[2] << 8 | (mDNSu32)x.b[3])); }
mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
{
return(x);
}
-mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v)
- {
- mDNSOpaque32 x;
- x.b[0] = (mDNSu8) (v >> 24) ;
- x.b[1] = (mDNSu8)((v >> 16) & 0xFF);
- x.b[2] = (mDNSu8)((v >> 8 ) & 0xFF);
- x.b[3] = (mDNSu8)((v ) & 0xFF);
- return x;
- }
-
#endif
// ***************************************************************************
extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
extern mStatus mDNS_StopQuery (mDNS *const m, DNSQuestion *const question);
+extern mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question);
extern mStatus mDNS_Reconfirm (mDNS *const m, CacheRecord *const cacherr);
extern mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr);
+extern void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr);
extern mDNSs32 mDNS_TimeNow(const mDNS *const m);
+extern mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *traversal);
+extern mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traversal);
+extern mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal);
+
+extern DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name);
+
// ***************************************************************************
#if 0
#pragma mark - Platform support functions that are accessible to the client layer too
// via mDNS_RemoveRecordFromService, or by deregistering the service. mDNS_RemoveRecordFromService is passed a
// callback to free the memory associated with the extra RR when it is safe to do so. The ExtraResourceRecord
// object can be found in the record's context pointer.
-
+
// mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers
// are a list of PTR records indicating (in the rdata) domains that are recommended for browsing.
// After getting the list of domains to browse, call mDNS_StopQuery to end the search.
{
mDNS_DomainTypeBrowse = 0,
mDNS_DomainTypeBrowseDefault = 1,
- mDNS_DomainTypeBrowseLegacy = 2,
+ mDNS_DomainTypeBrowseAutomatic = 2,
mDNS_DomainTypeRegistration = 3,
mDNS_DomainTypeRegistrationDefault = 4,
-
+
mDNS_DomainTypeMax = 4
} mDNS_DomainType;
extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname);
#define mDNS_StopAdvertiseDomains mDNS_Deregister
+extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
+
// ***************************************************************************
#if 0
#pragma mark - DNS name utility functions
// A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory,
// because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size.
// This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
-#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC)->c, (DST)->c, DomainNameLength((SRC)))
+#define AssignDomainName(DST, SRC) do { mDNSu16 len = DomainNameLength((SRC)); \
+ if (len <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len); else (DST)->c[0] = 0; } while(0)
// Comparison functions
+#define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0]))
extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
+extern mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2);
extern mDNSBool IsLocalDomain(const domainname *d); // returns true for domains that by default should be looked up using link-local multicast
// Get total length of domain name, in native DNS format, including terminal root label
// (e.g. length of "com." is 5 (length byte, three data bytes, final zero)
-extern mDNSu16 DomainNameLength(const domainname *const name);
+extern mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit);
+#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME + 1)
// Append functions to append one or more labels to an existing native format domain name:
// AppendLiteralLabelString adds a single label from a literal C string, with no escape character interpretation.
#define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
-extern mDNSBool IsPrivateV4Addr(mDNSAddr *addr); // returns true for RFC1918 private addresses
+extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1918 private addresses
+#define mDNSAddrIsRFC1918(X) ((X)->type == mDNSAddrType_IPv4 && mDNSv4AddrIsRFC1918(&(X)->ip.v4))
+#define mDNSSameIPPort(A,B) ((A).NotAnInteger == (B).NotAnInteger)
+#define mDNSSameOpaque16(A,B) ((A).NotAnInteger == (B).NotAnInteger)
#define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
#define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
#define mDNSSameEthAddress(A,B) ((A)->w[0] == (B)->w[0] && (A)->w[1] == (B)->w[1] && (A)->w[2] == (B)->w[2])
+#define mDNSSameOpaque64(A,B) ((A)->l[0] == (B)->l[0] && (A)->l[1] == (B)->l[1])
+#define mDNSOpaque64IsZero(A) ((A)->l[0] == 0 && (A)->l[1] == 0)
+
+#define mDNSIPPortIsZero(A) mDNSSameIPPort((A), zeroIPPort)
+#define mDNSOpaque16IsZero(A) mDNSSameOpaque16((A), zeroIPPort)
#define mDNSIPv4AddressIsZero(A) mDNSSameIPv4Address((A), zerov4Addr)
#define mDNSIPv6AddressIsZero(A) mDNSSameIPv6Address((A), zerov6Addr)
#define mDNSIPv4AddressIsOnes(A) mDNSSameIPv4Address((A), onesIPv4Addr)
#define mDNSIPv6AddressIsOnes(A) mDNSSameIPv6Address((A), onesIPv6Addr)
-#define mDNSAddressIsAllDNSLinkGroup(X) ( \
- ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroupv4)) || \
- ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) )
+#define mDNSAddressIsAllDNSLinkGroup(X) ( \
+ ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup_v4.ip.v4)) || \
+ ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroup_v6.ip.v6)) )
#define mDNSAddressIsZero(X) ( \
((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4)) || \
((X)->type == mDNSAddrType_IPv4) ? !(mDNSIPv4AddressIsZero((X)->ip.v4) || mDNSIPv4AddressIsOnes((X)->ip.v4)) : \
((X)->type == mDNSAddrType_IPv6) ? !(mDNSIPv6AddressIsZero((X)->ip.v6) || mDNSIPv6AddressIsOnes((X)->ip.v6)) : mDNSfalse)
+#define mDNSv4AddressIsLinkLocal(X) ((X)->b[0] == 169 && (X)->b[1] == 254)
+#define mDNSv6AddressIsLinkLocal(X) ((X)->b[0] == 0xFE && ((X)->b[1] & 0xC0) == 0x80)
+
+#define mDNSAddressIsLinkLocal(X) ( \
+ ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLinkLocal(&(X)->ip.v4) : \
+ ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLinkLocal(&(X)->ip.v6) : mDNSfalse)
// ***************************************************************************
#if 0
#pragma mark - Authentication Support
#endif
-#define HMAC_LEN 64
-#define HMAC_IPAD 0x36
-#define HMAC_OPAD 0x5c
-#define MD5_LEN 16
-
-// padded keys for inned/outer hash rounds
-typedef struct
- {
- mDNSu8 ipad[HMAC_LEN];
- mDNSu8 opad[HMAC_LEN];
- } HMAC_Key;
-
-// Internal data structure to maintain authentication information for an update domain
-typedef struct uDNS_AuthInfo
- {
- domainname zone;
- domainname keyname;
- HMAC_Key key;
- struct uDNS_AuthInfo *next;
- } uDNS_AuthInfo;
-
// Unicast DNS and Dynamic Update specific Client Calls
//
-// mDNS_SetSecretForZone tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret)
+// mDNS_SetSecretForDomain tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret)
// when dynamically updating a given zone (and its subdomains). The key used in authentication must be in
// domain name format. The shared secret must be a null-terminated base64 encoded string. A minimum size of
// 16 bytes (128 bits) is recommended for an MD5 hash as per RFC 2485.
// Calling this routine multiple times for a zone replaces previously entered values. Call with a NULL key
// to dissable authentication for the zone.
-extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret);
+extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
+ const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel);
// Hostname/Unicast Interface Configuration
// All hostnames advertised point to one IPv4 address and/or one IPv6 address, set via SetPrimaryInterfaceInfo. Invoking this routine
// updates all existing hostnames to point to the new address.
-
+
// A hostname is added via AddDynDNSHostName, which points to the primary interface's v4 and/or v6 addresss
// The status callback is invoked to convey success or failure codes - the callback should not modify the AuthRecord or free memory.
// these values are initialized.
// When routable V4 interfaces are added or removed, mDNS_UpdateLLQs should be called to re-estabish LLQs in case the
-// destination address for events (i.e. the route) has changed. For performance reasons, the caller is responsible for
+// destination address for events (i.e. the route) has changed. For performance reasons, the caller is responsible for
// batching changes, e.g. calling the routine only once if multiple interfaces are simultanously removed or added.
-// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer, and may later be removed via mDNS_DeleteDNSServers.
+// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer.
// For "split" DNS configurations, in which queries for different domains are sent to different servers (e.g. VPN and external),
// a domain may be associated with a DNS server. For standard configurations, specify the root label (".") or NULL.
-
+
extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
extern void mDNS_UpdateLLQs(mDNS *m);
-extern void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *dnsAddr, const domainname *domain);
-extern void mDNS_DeleteDNSServers(mDNS *const m);
+extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port);
+extern void mDNS_AddSearchDomain(const domainname *const domain);
-// Routines called by the core, exported by DNSDigest.c
+#define mDNS_AddSearchDomain_CString(X) \
+ do { domainname d; if ((X) && MakeDomainNameFromDNSNameString(&d, (X)) && d.c[0]) mDNS_AddSearchDomain(&d); } while(0)
-// Convert a base64 encoded key into a binary byte stream
-extern mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize);
+// Routines called by the core, exported by DNSDigest.c
-// Convert an arbitrary binary key (of any length) into an HMAC key (stored in AuthInfo struct)
-extern void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len);
+// Convert an arbitrary base64 encoded key key into an HMAC key (stored in AuthInfo struct)
+extern mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key);
-// sign a DNS message. The message must be compete, with all values in network byte order. end points to the end
+// sign a DNS message. The message must be complete, with all values in network byte order. end points to the end
// of the message, and is modified by this routine. numAdditionals is a pointer to the number of additional
// records in HOST byte order, which is incremented upon successful completion of this routine. The function returns
// the new end pointer on success, and NULL on failure.
-extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info);
+extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode);
+
+// verify a DNS message. The message must be complete, with all values in network byte order. end points to the
+// end of the record. tsig is a pointer to the resource record that contains the TSIG OPT record. info is
+// the matching key to use for verifying the message. This function expects that the additionals member
+// of the DNS message header has already had one subtracted from it.
+extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord *tsig, DomainAuthInfo *info, mDNSu16 *rcode, mDNSu16 *tcode);
// ***************************************************************************
#if 0
extern void mDNSPlatformLock (const mDNS *const m);
extern void mDNSPlatformUnlock (const mDNS *const m);
-extern void mDNSPlatformStrCopy (const void *src, void *dst);
-extern mDNSu32 mDNSPlatformStrLen (const void *src);
-extern void mDNSPlatformMemCopy (const void *src, void *dst, mDNSu32 len);
-extern mDNSBool mDNSPlatformMemSame (const void *src, const void *dst, mDNSu32 len);
-extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len);
+extern void mDNSPlatformStrCopy ( void *dst, const void *src);
+extern mDNSu32 mDNSPlatformStrLen ( const void *src);
+extern void mDNSPlatformMemCopy ( void *dst, const void *src, mDNSu32 len);
+extern mDNSBool mDNSPlatformMemSame (const void *dst, const void *src, mDNSu32 len);
+extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len);
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+#define mDNSPlatformMemAllocate(X) mallocL(#X, X)
+#else
extern void * mDNSPlatformMemAllocate (mDNSu32 len);
+#endif
extern void mDNSPlatformMemFree (void *mem);
extern mDNSu32 mDNSPlatformRandomSeed (void);
extern mStatus mDNSPlatformTimeInit (void);
// Platform support modules should provide the following functions to map between opaque interface IDs
// and interface indexes in order to support the DNS-SD API. If your target platform does not support
// multiple interfaces and/or does not support the DNS-SD API, these functions can be empty.
-extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index);
-extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id);
+extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index);
+extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id);
// Every platform support module must provide the following functions if it is to support unicast DNS
// and Dynamic Update.
// asynchronously fails, the TCPConnectionCallback should be invoked as usual, with the error being
// returned in subsequent calls to PlatformReadTCP or PlatformWriteTCP. (This allows for platforms
// with limited asynchronous error detection capabilities.) PlatformReadTCP and PlatformWriteTCP must
-// return the number of bytes read/written, 0 if the call would block, and -1 if an error.
+// return the number of bytes read/written, 0 if the call would block, and -1 if an error. PlatformReadTCP
+// should set the closed argument if the socket has been closed.
// PlatformTCPCloseConnection must close the connection to the peer and remove the descriptor from the
// event loop. CloseConnectin may be called at any time, including in a ConnectionCallback.
-typedef void (*TCPConnectionCallback)(int sd, void *context, mDNSBool ConnectionEstablished);
-extern mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context, int *descriptor);
-extern void mDNSPlatformTCPCloseConnection(int sd);
-extern int mDNSPlatformReadTCP(int sd, void *buf, int buflen);
-extern int mDNSPlatformWriteTCP(int sd, const char *msg, int len);
+typedef enum
+ {
+ kTCPSocketFlags_Zero = 0,
+ kTCPSocketFlags_UseTLS = (1 << 0)
+ } TCPSocketFlags;
+
+typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err);
+extern TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port); // creates a TCP socket
+extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
+extern int mDNSPlatformTCPGetFD(TCPSocket *sock);
+extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+ TCPConnectionCallback callback, void *context);
+extern void mDNSPlatformTCPCloseConnection(TCPSocket *sock);
+extern long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
+extern long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len);
+extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, mDNSIPPort port);
+extern void mDNSPlatformUDPClose(UDPSocket *sock);
+
+// mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd
+extern mStatus mDNSPlatformTLSSetupCerts(void);
+extern void mDNSPlatformTLSTearDownCerts(void);
// Platforms that support unicast browsing and dynamic update registration for clients who do not specify a domain
// in browse/registration calls must implement these routines to get the "default" browse/registration list.
-// The Get() functions must return a linked list of DNameListElem structs, allocated via mDNSPlatformMemAllocate.
-// Platforms may implement the Get() calls via the mDNS_CopyDNameList() helper routine.
-// Callers should free lists obtained via the Get() calls with th mDNS_FreeDNameList routine, provided by the core.
-
-typedef struct DNameListElem
- {
- domainname name;
- struct DNameListElem *next;
- } DNameListElem;
-
-extern DNameListElem *mDNSPlatformGetSearchDomainList(void);
-extern DNameListElem *mDNSPlatformGetRegDomainList(void);
-// Helper functions provided by the core
-extern DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig);
-extern void mDNS_FreeDNameList(DNameListElem *list);
+extern void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains);
+extern mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
+extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
#ifdef _LEGACY_NAT_TRAVERSAL_
// Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
-
-#define DYN_PORT_MIN 49152 // ephemeral port range
-#define DYN_PORT_MAX 65535
-#define LEGACY_NATMAP_MAX_TRIES 4 // if our desired mapping is taken, how many times we try mapping to a random port
-
-extern mStatus LNT_GetPublicIP(mDNSOpaque32 *ip);
-extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp);
-extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp);
+extern void LNT_SendDiscoveryMsg(mDNS *m);
+extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len);
+extern mStatus LNT_GetExternalAddress(mDNS *m);
+extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n);
+extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n);
#endif // _LEGACY_NAT_TRAVERSAL_
// The core mDNS code provides these functions, for the platform support code to call at appropriate times
// not lightweight second-by-second CPU power management modes.)
extern void mDNS_SetFQDN(mDNS *const m);
-extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay);
-extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set);
+extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping);
+extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping);
extern void mDNSCoreInitComplete(mDNS *const m, mStatus result);
extern void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
+extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg);
+extern void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease);
+extern void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds);
+extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr);
+extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
+
+// For now this AutoTunnel stuff is specific to Mac OS X.
+// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
+#if APPLE_OSX_mDNSResponder
+extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
+extern void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q);
+extern void SetupLocalAutoTunnelInterface_internal(mDNS *const m);
+#endif
+
// ***************************************************************************
#if 0
#pragma mark - Compile-Time assertion checks
// what's wrong until you run the software. This way, if the assertion condition
// is false, the array size is negative, and the complier complains immediately.
-struct mDNS_CompileTimeAssertionChecks
+struct CompileTimeAssertionChecks_mDNS
{
// Check that the compiler generated our on-the-wire packet format structure definitions
// properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
char assertA[(sizeof(mDNSOpaque32) == 4 ) ? 1 : -1];
char assertB[(sizeof(mDNSOpaque128) == 16 ) ? 1 : -1];
char assertC[(sizeof(CacheRecord ) >= sizeof(CacheGroup) ) ? 1 : -1];
+ char assertD[(sizeof(int) >= 4 ) ? 1 : -1];
+ char assertE[(StandardAuthRDSize >= 256 ) ? 1 : -1];
+
+ // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
+ // other overly-large structures instead of having a pointer to them, can inadvertently
+ // cause structure sizes (and therefore memory usage) to balloon unreasonably.
+ char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 40) ? 1 : -1];
+ char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1290) ? 1 : -1];
+ char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 170) ? 1 : -1];
+ char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 170) ? 1 : -1];
+ char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 700) ? 1 : -1];
+ char sizecheck_ZoneData [(sizeof(ZoneData) <= 1600) ? 1 : -1];
+ char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 140) ? 1 : -1];
+ char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3000) ? 1 : -1];
+ char sizecheck_DNSServer [(sizeof(DNSServer) <= 300) ? 1 : -1];
+ char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 4000) ? 1 : -1];
+ char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5700) ? 1 : -1];
+ char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 6000) ? 1 : -1];
+ char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 2900) ? 1 : -1];
+#if APPLE_OSX_mDNSResponder
+ char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1040) ? 1 : -1];
+#endif
};
// ***************************************************************************
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
*
- * @APPLE_LICENSE_HEADER_START@
+ * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- Change History (most recent first):
+ * To Do:
+ * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code
+ * is supposed to be malloc-free so that it runs in constant memory determined at compile-time.
+ * Any dynamic run-time requirements should be handled by the platform layer below or client layer above
+
+ Change History (most recent first):
$Log: uDNS.c,v $
-Revision 1.225 2005/10/21 22:51:17 cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-Refinement: Shorten "check-for-broken-dns-relay" to just "dnsbugtest"
-to avoid crashing NAT gateways that have a different DNS relay bug
+Revision 1.496 2007/10/04 22:38:59 cheshire
+Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
+
+Revision 1.495 2007/10/03 00:16:19 cheshire
+In startPrivateQueryCallback, need to grab lock before calling SetNextQueryTime
+
+Revision 1.494 2007/10/02 21:11:08 cheshire
+<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
+
+Revision 1.493 2007/10/02 19:50:23 cheshire
+Improved debugging message
+
+Revision 1.492 2007/09/29 03:15:43 cheshire
+<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
+Use AutoTunnelUnregistered macro instead of checking record state directly
+
+Revision 1.491 2007/09/29 01:33:45 cheshire
+<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
+
+Revision 1.490 2007/09/29 01:06:17 mcguire
+<rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
+
+Revision 1.489 2007/09/27 22:02:33 cheshire
+<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
+
+Revision 1.488 2007/09/27 21:20:17 cheshire
+Improved debugging syslog messages
+
+Revision 1.487 2007/09/27 18:55:11 cheshire
+<rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
+
+Revision 1.486 2007/09/27 17:42:49 cheshire
+Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
+
+Revision 1.485 2007/09/27 02:16:30 cheshire
+<rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port
+
+Revision 1.484 2007/09/27 00:25:39 cheshire
+Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
+<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
+
+Revision 1.483 2007/09/26 23:16:58 cheshire
+<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
+
+Revision 1.482 2007/09/26 22:06:02 cheshire
+<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
+
+Revision 1.481 2007/09/26 00:49:46 cheshire
+Improve packet logging to show sent and received packets,
+transport protocol (UDP/TCP/TLS) and source/destination address:port
+
+Revision 1.480 2007/09/21 21:08:52 cheshire
+Get rid of unnecessary DumpPacket() calls -- it makes more sense
+to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
+
+Revision 1.479 2007/09/21 20:01:17 cheshire
+<rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear
+
+Revision 1.478 2007/09/21 19:29:14 cheshire
+Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
+
+Revision 1.477 2007/09/20 02:29:37 cheshire
+<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
+
+Revision 1.476 2007/09/20 01:19:49 cheshire
+Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
+
+Revision 1.475 2007/09/19 23:51:26 cheshire
+<rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails
+
+Revision 1.474 2007/09/19 20:32:09 cheshire
+Export GetAuthInfoForName so it's callable from other files
+
+Revision 1.473 2007/09/18 21:42:29 cheshire
+To reduce programming mistakes, renamed ExtPort to RequestedPort
+
+Revision 1.472 2007/09/14 21:26:08 cheshire
+<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
+
+Revision 1.471 2007/09/14 01:07:10 cheshire
+If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
+got a DHCP address yet) then retry periodically until it gives us a real address.
+
+Revision 1.470 2007/09/13 00:36:26 cheshire
+<rdar://problem/5477360> NAT Reboot detection logic incorrect
+
+Revision 1.469 2007/09/13 00:28:50 cheshire
+<rdar://problem/5477354> Host records not updated on NAT address change
+
+Revision 1.468 2007/09/13 00:16:41 cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
+
+Revision 1.467 2007/09/12 23:03:08 cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-Revision 1.224 2005/10/20 00:10:33 cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
+Revision 1.466 2007/09/12 22:19:29 cheshire
+<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
-Revision 1.223 2005/10/17 18:52:42 cheshire
-<rdar://problem/4271183> mDNSResponder crashed in CheckRecordRegistrations
-Move code to unregister the service's extra records from uDNS_DeregisterService() to unlinkSRS().
+Revision 1.465 2007/09/12 19:22:19 cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-Revision 1.222 2005/10/05 23:04:10 cheshire
-Add more information to unlinkAR and startLLQHandshakeCallback error messages
+Revision 1.464 2007/09/12 01:22:13 cheshire
+Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
-Revision 1.221 2005/10/05 17:27:48 herscher
-<rdar://problem/4272516> Change 200ms delay to 10ms
+Revision 1.463 2007/09/11 20:23:28 vazquez
+<rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
+Make sure we clean up NATTraversals before free'ing HostnameInfo
-Revision 1.220 2005/09/24 01:10:09 cheshire
-Fix comment typos
+Revision 1.462 2007/09/11 19:19:16 cheshire
+Correct capitalization of "uPNP" to "UPnP"
-Revision 1.219 2005/09/22 07:28:25 herscher
-Double the delay to 200000 usec after sending out a DNS query
+Revision 1.461 2007/09/10 22:08:17 cheshire
+Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
-Revision 1.218 2005/09/13 01:06:14 herscher
-<rdar://problem/4248878> Add 100ms delay in sendQuery.
+Revision 1.460 2007/09/07 21:47:43 vazquez
+<rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
+Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
-Revision 1.217 2005/08/04 18:08:24 cheshire
-Update comments
+Revision 1.459 2007/09/07 01:01:05 cheshire
+<rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
+In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
-Revision 1.216 2005/07/29 23:05:22 ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
-Services should point to IPv6 address if IPv4 NAT mapping fails
+Revision 1.458 2007/09/06 19:14:33 cheshire
+Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
-Revision 1.215 2005/07/29 21:01:51 ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
-correction to original checkin - misplaced return in HostnameCallback and logic error determining v6 changes
+Revision 1.457 2007/09/05 21:48:01 cheshire
+<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
+Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs
+to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
+otherwise those records will expire and vanish from the cache.
-Revision 1.214 2005/07/29 19:46:10 ksekar
-<rdar://problem/4191860> reduce polling period on failed LLQs to 15 minutes
+Revision 1.456 2007/09/05 21:00:17 cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in startPrivateQueryCallback
-Revision 1.213 2005/07/29 18:04:22 ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
+Revision 1.455 2007/09/05 20:53:06 cheshire
+Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
-Revision 1.212 2005/07/22 19:35:50 ksekar
-<rdar://problem/4188821> SUTiger: LLQ event acknowledgments are not formated correctly
+Revision 1.454 2007/09/05 02:32:55 cheshire
+Fixed posix build error (mixed declarations and code)
-Revision 1.211 2005/07/21 18:51:04 ksekar
-<rdar://problem/4103136> mDNSResponder times out when mapping ports after sleep
+Revision 1.453 2007/09/05 02:26:57 cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+In startPrivateQueryCallback, restore q->ThisQInterval to non-zero value after GetZoneData completes
-Revision 1.210 2005/07/21 18:47:31 ksekar
-<rdar://problem/4137283> NAT-PMP refresh Requested Public Port should contain actual mapped port
+Revision 1.452 2007/08/31 22:58:22 cheshire
+If we have an existing TCP connection we should re-use it instead of just bailing out
+After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
-Revision 1.209 2005/07/04 21:16:37 cheshire
-Minor code tidying -- initialize variables where they are declared
+Revision 1.451 2007/08/31 18:49:49 vazquez
+<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
-Revision 1.208 2005/06/28 00:24:28 ksekar
-<rdar://problem/4157823> memory smasher in conQueryCallback
+Revision 1.450 2007/08/30 22:50:04 mcguire
+<rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
-Revision 1.207 2005/05/13 20:45:10 ksekar
-<rdar://problem/4074400> Rapid wide-area txt record updates don't work
+Revision 1.449 2007/08/30 00:43:17 cheshire
+Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
-Revision 1.206 2005/03/31 02:19:55 cheshire
-<rdar://problem/4021486> Fix build warnings
-Reviewed by: Scott Herscher
+Revision 1.448 2007/08/30 00:18:46 cheshire
+<rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
-Revision 1.205 2005/03/21 00:33:51 shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
+Revision 1.447 2007/08/29 01:18:33 cheshire
+<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
+Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
-Revision 1.204 2005/03/16 00:42:32 ksekar
-<rdar://problem/4012279> Long-lived queries not working on Windows
+Revision 1.446 2007/08/28 23:58:42 cheshire
+Rename HostTarget -> AutoTarget
-Revision 1.203 2005/03/04 03:00:03 ksekar
-<rdar://problem/4026546> Retransmissions happen too early, causing registrations to conflict with themselves
+Revision 1.445 2007/08/28 23:53:21 cheshire
+Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
-Revision 1.202 2005/03/01 19:29:17 ksekar
-changed LogMsgs to debugfs
+Revision 1.444 2007/08/27 20:29:20 cheshire
+Additional debugging messages
-Revision 1.201 2005/02/26 03:04:13 cheshire
-<rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
-Don't try to do updates to root name server. This ensures status dot turns red if user
-enters a bad host name such as just "fred" instead of a properly fully-qualified name.
+Revision 1.443 2007/08/24 23:18:28 cheshire
+mDNS_SetSecretForDomain is called with lock held; needs to use
+GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
-Revision 1.200 2005/02/25 17:47:45 ksekar
-<rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
+Revision 1.442 2007/08/24 22:43:06 cheshire
+Tidied up coded layout
-Revision 1.199 2005/02/25 04:21:00 cheshire
-<rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
+Revision 1.441 2007/08/24 01:20:55 cheshire
+<rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
-Revision 1.198 2005/02/25 02:35:22 cheshire
-<rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
-If we get NXDomain error looking for the _dns-update._udp record,
-update status from 1 (in progress) to mStatus_NoSuchNameErr (failed)
+Revision 1.440 2007/08/24 00:15:20 cheshire
+Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
-Revision 1.197 2005/02/24 21:56:59 ksekar
-Change LogMsgs to debugfs
+Revision 1.439 2007/08/23 21:47:09 vazquez
+<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
+make sure we clean up port mappings on base stations by sending a lease value of 0,
+and only send NAT-PMP packets on private networks; also save some memory by
+not using packet structs in NATTraversals.
-Revision 1.196 2005/02/24 21:52:28 ksekar
-<rdar://problem/3922768> Remove "deferred deregistration" logic for hostnames
+Revision 1.438 2007/08/22 17:50:08 vazquez
+<rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
+Propagate router errors to clients, and stop logging spurious "message too short" logs.
-Revision 1.195 2005/02/22 17:53:08 ksekar
-Changed successful NAT Traversals from LogMsg to LogOperation
+Revision 1.437 2007/08/18 00:54:15 mcguire
+<rdar://problem/5413147> BTMM: Should not register private addresses or zeros
-Revision 1.194 2005/02/15 18:38:03 ksekar
-<rdar://problem/3967876> change expected/redundant log messages to debugfs.
+Revision 1.436 2007/08/08 21:07:48 vazquez
+<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
-Revision 1.193 2005/02/15 01:17:48 ksekar
-Fixed build failure.
+Revision 1.435 2007/08/03 02:04:09 vazquez
+<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
+Fix case where NAT-PMP returns an external address but does not support
+port mappings. Undo previous change and now, if the router returns an
+error in the reply packet we respect it.
-Revision 1.192 2005/02/14 23:01:28 ksekar
-Refinement to previous checkin - don't log bad LLQ opcode if we had to send the request more than once.
+Revision 1.434 2007/08/02 21:03:05 vazquez
+Change NAT logic to fix case where base station with port mapping turned off
+returns an external address but does not make port mappings.
-Revision 1.191 2005/02/14 18:26:51 ksekar
-<rdar://problem/4005569> mDNSResponder complains about bad LLQ Opcode 2
+Revision 1.433 2007/08/02 03:30:11 vazquez
+<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
-Revision 1.190 2005/02/11 19:44:06 shersche
-Remove extra semicolon at end of line
+Revision 1.432 2007/08/01 18:15:19 cheshire
+Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
-Revision 1.189 2005/02/10 21:07:02 ksekar
-Don't goto error in ReceiveNATAddrResponse if we receive a malformatted response
+Revision 1.431 2007/08/01 16:11:06 cheshire
+Fixed "mixed declarations and code" compiler error in Posix build
-Revision 1.188 2005/02/10 02:02:44 ksekar
-Remove double semi-colon
+Revision 1.430 2007/08/01 16:09:13 cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-Revision 1.187 2005/02/09 23:28:01 ksekar
-<rdar://problem/3984374> NAT-PMP response callback should return a
-boolean indicating if the packet matched the request
+Revision 1.429 2007/08/01 03:09:22 cheshire
+<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
-Revision 1.186 2005/02/04 21:56:29 ksekar
-<rdar://problem/3984374> Simultaneous port map requests sometimes fail
-- Refinement to previous checkin.
+Revision 1.428 2007/08/01 01:43:36 cheshire
+Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
-Revision 1.185 2005/02/03 23:48:22 ksekar
-<rdar://problem/3984374> Simultaneous port map requests sometimes fail
+Revision 1.427 2007/08/01 01:31:13 cheshire
+Need to initialize traversal->tcpInfo fields or code may crash
-Revision 1.184 2005/02/01 19:33:29 ksekar
-<rdar://problem/3985239> Keychain format too restrictive
+Revision 1.426 2007/08/01 01:15:57 cheshire
+<rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network
-Revision 1.183 2005/01/27 22:57:55 cheshire
-Fix compile errors on gcc4
+Revision 1.425 2007/08/01 00:04:14 cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
-Revision 1.182 2005/01/25 18:55:05 ksekar
-Shortened log message
+Revision 1.424 2007/07/31 02:28:35 vazquez
+<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-Revision 1.181 2005/01/25 02:17:32 cheshire
-<rdar://problem/3971263> Don't use query ID zero in uDNS queries
+Revision 1.423 2007/07/30 23:31:26 cheshire
+Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
-Revision 1.180 2005/01/19 21:01:54 ksekar
-<rdar://problem/3955355> uDNS needs to support subtype registration and browsing
+Revision 1.422 2007/07/28 01:25:57 cheshire
+<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
-Revision 1.179 2005/01/19 19:15:35 ksekar
-Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
+Revision 1.421 2007/07/28 00:04:14 cheshire
+Various fixes for comments and debugging messages
-Revision 1.178 2005/01/17 23:47:58 cheshire
-<rdar://problem/3904954> Wide-area services not found on little-endian
+Revision 1.420 2007/07/27 23:59:18 cheshire
+Added compile-time structure size checks
-Revision 1.177 2005/01/17 23:41:26 cheshire
-Fix compile errors
+Revision 1.419 2007/07/27 20:52:29 cheshire
+Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
-Revision 1.176 2005/01/17 21:03:04 cheshire
-<rdar://problem/3904954> Wide-area services not found on little-endian
+Revision 1.418 2007/07/27 20:32:05 vazquez
+Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
+calls to mDNS_StopNATOperation() go through the UPnP code
-Revision 1.175 2005/01/15 00:56:41 ksekar
-<rdar://problem/3954575> Unicast services don't disappear when logging
-out of VPN
+Revision 1.417 2007/07/27 20:19:42 cheshire
+Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
-Revision 1.174 2005/01/14 18:44:28 ksekar
-<rdar://problem/3954609> mDNSResponder is crashing when changing domains
+Revision 1.416 2007/07/27 19:59:28 cheshire
+MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
-Revision 1.173 2005/01/14 18:34:22 ksekar
-<rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
+Revision 1.415 2007/07/27 19:51:01 cheshire
+Use symbol QC_addnocache instead of literal constant "2"
-Revision 1.172 2005/01/11 22:50:52 ksekar
-Fixed constant naming (was using kLLQ_DefLease for update leases)
+Revision 1.414 2007/07/27 19:30:39 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
-Revision 1.171 2005/01/10 04:52:49 ksekar
-Changed LogMsg to debugf
+Revision 1.413 2007/07/27 18:44:01 cheshire
+Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
-Revision 1.170 2005/01/08 00:50:05 ksekar
-Fixed spelling mistake in log msg
+Revision 1.412 2007/07/27 18:38:56 cheshire
+Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
-Revision 1.169 2005/01/08 00:42:18 ksekar
-<rdar://problem/3922758> Clean up syslog messages
+Revision 1.411 2007/07/27 00:57:13 cheshire
+Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
-Revision 1.168 2004/12/23 23:22:47 ksekar
-<rdar://problem/3933606> Unicast known answers "name" pointers point to garbage stack memory
+Revision 1.410 2007/07/25 21:41:00 vazquez
+Make sure we clean up opened sockets when there are network transitions and when changing
+port mappings
-Revision 1.167 2004/12/22 22:25:47 ksekar
-<rdar://problem/3734265> NAT-PMP: handle location changes
+Revision 1.409 2007/07/25 03:05:02 vazquez
+Fixes for:
+<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
+<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
+and a myriad of other security problems
-Revision 1.166 2004/12/22 00:04:12 ksekar
-<rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply
+Revision 1.408 2007/07/24 21:47:51 cheshire
+Don't do mDNS_StopNATOperation() for operations we never started
-Revision 1.165 2004/12/18 03:14:22 cheshire
-DblNAT -> DoubleNAT
+Revision 1.407 2007/07/24 17:23:33 cheshire
+<rdar://problem/5357133> Add list validation checks for debugging
-Revision 1.164 2004/12/17 03:55:40 ksekar
-Don't use -1 as special meaning for expiration timer (it is a valid
-value, and is redundant with our state variables)
+Revision 1.406 2007/07/24 04:14:30 cheshire
+<rdar://problem/5356281> LLQs not working in with NAT Traversal
-Revision 1.163 2004/12/17 03:51:53 ksekar
-<rdar://problem/3920991> Don't update TXT record if service registration fails
+Revision 1.405 2007/07/24 01:29:03 cheshire
+<rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
-Revision 1.162 2004/12/17 01:29:11 ksekar
-<rdar://problem/3920598> Questions can go deaf on location changes
+Revision 1.404 2007/07/20 23:10:51 cheshire
+Fix code layout
-Revision 1.161 2004/12/16 20:42:02 cheshire
-Fix compiler warnings
+Revision 1.403 2007/07/20 20:12:37 cheshire
+Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
-Revision 1.160 2004/12/16 20:13:00 cheshire
-<rdar://problem/3324626> Cache memory management improvements
+Revision 1.402 2007/07/20 00:54:20 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Revision 1.159 2004/12/15 02:11:22 ksekar
-<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
+Revision 1.401 2007/07/18 03:23:33 cheshire
+In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
-Revision 1.158 2004/12/15 02:04:28 ksekar
-Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails
+Revision 1.400 2007/07/18 02:30:25 cheshire
+Defer AutoTunnel server record advertising until we have at least one service to advertise
+Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
-Revision 1.157 2004/12/15 01:39:21 ksekar
-Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails
+Revision 1.399 2007/07/18 01:02:28 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
-Revision 1.156 2004/12/15 01:18:57 ksekar
-<rdar://problem/3825979> Call DeregisterService on nat port map failure
+Revision 1.398 2007/07/16 23:54:48 cheshire
+<rdar://problem/5338850> Crash when removing or changing DNS keys
-Revision 1.155 2004/12/14 21:21:20 ksekar
-<rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
+Revision 1.397 2007/07/16 20:13:31 vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Revision 1.154 2004/12/14 20:52:27 cheshire
-Add question->qnamehash and cr->resrec.namehash to log message
+Revision 1.396 2007/07/14 00:33:04 cheshire
+Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
-Revision 1.153 2004/12/14 20:45:02 cheshire
-Improved error logging in "unexpected answer" message
+Revision 1.395 2007/07/12 23:56:23 cheshire
+Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
-Revision 1.152 2004/12/14 03:02:10 ksekar
-<rdar://problem/3919016> Rare race condition can cause crash
+Revision 1.394 2007/07/12 23:36:08 cheshire
+Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
-Revision 1.151 2004/12/13 21:45:08 ksekar
-uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer)
+Revision 1.393 2007/07/12 22:15:10 cheshire
+Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
-Revision 1.150 2004/12/13 20:42:41 ksekar
-Fixed LogMsg
+Revision 1.392 2007/07/12 02:51:27 cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Revision 1.149 2004/12/13 18:10:03 ksekar
-Fixed LogMsg
+Revision 1.391 2007/07/11 23:16:31 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
-Revision 1.148 2004/12/13 01:18:04 ksekar
-Fixed unused variable warning for non-debug builds
+Revision 1.390 2007/07/11 22:47:55 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
+In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
-Revision 1.147 2004/12/12 23:51:42 ksekar
-<rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
+Revision 1.389 2007/07/11 21:33:10 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Set up and register AutoTunnelTarget and AutoTunnelService DNS records
-Revision 1.146 2004/12/12 23:30:40 ksekar
-<rdar://problem/3916987> Extra RRs not properly unlinked when parent service registration fails
+Revision 1.388 2007/07/11 19:27:10 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
+For temporary testing fake up an IPv4LL address instead of IPv6 ULA
-Revision 1.145 2004/12/12 22:56:29 ksekar
-<rdar://problem/3668508> Need to properly handle duplicate long-lived queries
+Revision 1.387 2007/07/11 03:04:08 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
-Revision 1.144 2004/12/11 20:55:29 ksekar
-<rdar://problem/3916479> Clean up registration state machines
+Revision 1.386 2007/07/10 01:57:28 cheshire
+<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
+Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
+Made routines hold on to the reference it returns instead of leaking it
-Revision 1.143 2004/12/10 01:21:27 cheshire
-<rdar://problem/3914089> Get rid of "LLQ Responses over TCP not currently supported" message
+Revision 1.385 2007/07/09 23:50:18 cheshire
+unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
-Revision 1.142 2004/12/08 02:03:31 ksekar
-<rdar://problem/3865124> Looping on NAT Traversal error - check for
-NULL RR on error
+Revision 1.384 2007/07/06 21:20:21 cheshire
+Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
-Revision 1.141 2004/12/07 01:39:28 cheshire
-Don't fail if the same server is responsible for more than one domain
-(e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.)
+Revision 1.383 2007/07/06 18:59:59 cheshire
+Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
-Revision 1.140 2004/12/06 21:15:22 ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+Revision 1.382 2007/07/04 00:49:43 vazquez
+Clean up extraneous comments
-Revision 1.139 2004/12/06 19:08:03 cheshire
-Add clarifying comment -- CountLabels() excludes the final root label.
+Revision 1.381 2007/07/03 00:41:14 vazquez
+ More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
+ Safely deal with packet replies and client callbacks
-Revision 1.138 2004/12/06 01:45:54 ksekar
-Correct wording in LogMsg
+Revision 1.380 2007/07/02 22:08:47 cheshire
+Fixed crash in "Received public IP address" message
-Revision 1.137 2004/12/03 20:40:35 ksekar
-<rdar://problem/3865124> Looping on NAT Traversal error
+Revision 1.379 2007/06/29 00:08:49 vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-Revision 1.136 2004/12/03 07:20:50 ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
+Revision 1.378 2007/06/27 20:25:10 cheshire
+Expanded dnsbugtest comment, explaining requirement that we also need these
+test queries to black-hole before they get to the root name servers.
-Revision 1.135 2004/12/03 05:18:33 ksekar
-<rdar://problem/3810596> mDNSResponder needs to return more specific TSIG errors
+Revision 1.377 2007/06/22 21:27:21 cheshire
+Modified "could not convert shared secret from base64" log message
-Revision 1.134 2004/12/02 20:03:49 ksekar
-<rdar://problem/3889647> Still publishes wide-area domains even after switching to a local subnet
+Revision 1.376 2007/06/20 01:10:12 cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-Revision 1.133 2004/12/02 18:37:52 ksekar
-<rdar://problem/3758233> Registering with port number zero should not create a port mapping
+Revision 1.375 2007/06/15 21:54:51 cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-Revision 1.132 2004/12/01 20:57:19 ksekar
-<rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
+Revision 1.374 2007/06/12 02:15:26 cheshire
+Fix incorrect "DNS Server passed" LogOperation message
-Revision 1.131 2004/12/01 19:59:27 cheshire
-<rdar://problem/3882643> Crash in mDNSPlatformTCPConnect
-If a TCP response has the TC bit set, don't respond by just trying another TCP connection
+Revision 1.373 2007/05/31 00:25:43 cheshire
+<rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
-Revision 1.130 2004/12/01 02:43:23 cheshire
-Don't call StatusCallback if function pointer is null
+Revision 1.372 2007/05/25 17:03:45 cheshire
+lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
-Revision 1.129 2004/11/30 23:51:06 cheshire
-Remove double semicolons
+Revision 1.371 2007/05/24 00:11:44 cheshire
+Remove unnecessary lenbuf field from tcpInfo_t
-Revision 1.128 2004/11/25 01:48:30 ksekar
-<rdar://problem/3878991> Logging into VPN does not trigger registration of address record
+Revision 1.370 2007/05/23 00:30:59 cheshire
+Don't change question->TargetQID when repeating query over TCP
-Revision 1.127 2004/11/25 01:41:36 ksekar
-Changed unnecessary LogMsgs to debugfs
+Revision 1.369 2007/05/21 18:04:40 cheshire
+Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
-Revision 1.126 2004/11/23 23:54:17 ksekar
-<rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
-can crash mDNSResponder
+Revision 1.368 2007/05/17 19:12:16 cheshire
+Updated comment about finding matching pair of sockets
-Revision 1.125 2004/11/23 04:16:48 cheshire
-Removed receiveMsg() routine.
+Revision 1.367 2007/05/15 23:38:00 cheshire
+Need to grab lock before calling SendRecordRegistration();
-Revision 1.124 2004/11/23 04:06:51 cheshire
-Get rid of floating point constant -- in a small embedded device, bringing in all
-the floating point libraries just to halve an integer value is a bit too heavyweight.
+Revision 1.366 2007/05/15 00:43:05 cheshire
+<rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
-Revision 1.123 2004/11/22 17:16:20 ksekar
-<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+Revision 1.365 2007/05/10 21:19:18 cheshire
+Rate-limit DNS test queries to at most one per three seconds
+(useful when we have a dozen active WAB queries, and then we join a new network)
-Revision 1.122 2004/11/19 18:00:34 ksekar
-<rdar://problem/3682646> Security: use random ID for one-shot unicast queries
+Revision 1.364 2007/05/07 20:43:45 cheshire
+<rdar://problem/4241419> Reduce the number of queries and announcements
-Revision 1.121 2004/11/19 04:24:08 ksekar
-<rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
+Revision 1.363 2007/05/04 22:12:48 cheshire
+Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
+When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
-Revision 1.120 2004/11/19 02:32:43 ksekar
-<rdar://problem/3682608> Wide-Area Security: Add LLQ-ID to events
+Revision 1.362 2007/05/04 21:23:05 cheshire
+<rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response
+Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
-Revision 1.119 2004/11/18 23:21:24 ksekar
-<rdar://problem/3764544> LLQ Security: Need to verify src port/address for LLQ handshake
+Revision 1.361 2007/05/03 23:50:48 cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
+In the case of negative answers for the address record, set the server address to zerov4Addr
-Revision 1.118 2004/11/18 22:58:37 ksekar
-Removed old comment.
+Revision 1.360 2007/05/03 22:40:38 cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-Revision 1.117 2004/11/18 18:04:21 ksekar
-Restore checkins lost due to repository disk failure: Update comments & <rdar://problem/3880688>
+Revision 1.359 2007/05/02 22:21:33 cheshire
+<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-Revision 1.xxx 2004/11/17 06:17:57 cheshire
-Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
+Revision 1.358 2007/05/01 21:46:31 cheshire
+Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
-Revision 1.xxx 2004/11/17 00:45:28 ksekar
-<rdar://problem/3880688> Result of putUpdateLease not error-checked
+Revision 1.357 2007/05/01 01:33:49 cheshire
+Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
-Revision 1.116 2004/11/16 01:41:47 ksekar
-Fixed typo in debugf
+Revision 1.356 2007/04/30 21:51:06 cheshire
+Updated comments
-Revision 1.115 2004/11/15 20:09:24 ksekar
-<rdar://problem/3719050> Wide Area support for Add/Remove record
+Revision 1.355 2007/04/30 21:33:38 cheshire
+Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
+is iterating through the m->ServiceRegistrations list
-Revision 1.114 2004/11/13 02:32:47 ksekar
-<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
-- fixed incorrect state comparison in CheckQueries
+Revision 1.354 2007/04/30 01:30:04 cheshire
+GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
+RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
-Revision 1.113 2004/11/13 02:29:52 ksekar
-<rdar://problem/3878386> LLQ refreshes not reliable
+Revision 1.353 2007/04/28 01:28:25 cheshire
+Fixed memory leak on error path in FoundDomain
-Revision 1.112 2004/11/11 20:45:14 ksekar
-<rdar://problem/3876052> self-conflict test not compatible with some BIND servers
+Revision 1.352 2007/04/27 19:49:53 cheshire
+In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
-Revision 1.111 2004/11/11 20:14:55 ksekar
-<rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
+Revision 1.351 2007/04/27 19:28:02 cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
-Revision 1.110 2004/11/10 23:53:53 ksekar
-Remove no longer relevant comment
+Revision 1.350 2007/04/26 22:47:14 cheshire
+Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
-Revision 1.109 2004/11/10 20:40:53 ksekar
-<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+Revision 1.349 2007/04/26 16:04:06 cheshire
+In mDNS_AddDNSServer, check whether port matches
+In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
-Revision 1.108 2004/11/01 20:36:16 ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+Revision 1.348 2007/04/26 04:01:59 cheshire
+Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
-Revision 1.107 2004/10/26 06:11:41 cheshire
-Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+Revision 1.347 2007/04/26 00:35:15 cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
-Revision 1.106 2004/10/26 03:52:03 cheshire
-Update checkin comments
+Revision 1.346 2007/04/25 19:16:59 cheshire
+Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
-Revision 1.105 2004/10/26 01:15:06 cheshire
-Use "#if 0" instead of commenting out code
+Revision 1.345 2007/04/25 18:05:11 cheshire
+Don't try to restart inactive (duplicate) queries
-Revision 1.104 2004/10/25 21:41:38 ksekar
-<rdar://problem/3852958> wide-area name conflicts can cause crash
+Revision 1.344 2007/04/25 17:54:07 cheshire
+Don't cancel Private LLQs using a clear-text UDP packet
-Revision 1.103 2004/10/25 19:30:52 ksekar
-<rdar://problem/3827956> Simplify dynamic host name structures
+Revision 1.343 2007/04/25 16:40:08 cheshire
+Add comment explaining uDNS_recvLLQResponse logic
-Revision 1.102 2004/10/23 01:16:00 cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+Revision 1.342 2007/04/25 02:14:38 cheshire
+<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
+Additional fixes to make LLQs work properly
-Revision 1.101 2004/10/22 20:52:07 ksekar
-<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+Revision 1.341 2007/04/24 02:07:42 cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
+Deleted some more redundant code
-Revision 1.100 2004/10/20 02:16:41 cheshire
-Improve "could not confirm existence of NS record" error message
-Don't call newRR->RecordCallback if it is NULL
+Revision 1.340 2007/04/23 22:01:23 cheshire
+<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
+As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
+advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
+probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
-Revision 1.99 2004/10/19 21:33:18 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+Revision 1.339 2007/04/22 06:02:03 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.98 2004/10/16 00:16:59 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.338 2007/04/21 19:44:11 cheshire
+Improve uDNS_HandleNATPortMapReply log message
-Revision 1.97 2004/10/15 23:00:18 ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
+Revision 1.337 2007/04/21 02:03:00 cheshire
+Also need to set AddressRec->resrec.RecordType in the NAT case too
-Revision 1.96 2004/10/12 23:30:44 ksekar
-<rdar://problem/3609944> mDNSResponder needs to follow CNAME referrals
+Revision 1.336 2007/04/20 21:16:12 cheshire
+Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
+Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
-Revision 1.95 2004/10/12 03:15:09 ksekar
-<rdar://problem/3835612> mDNS_StartQuery shouldn't return transient no-server error
+Revision 1.335 2007/04/19 23:57:20 cheshire
+Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
-Revision 1.94 2004/10/12 02:49:20 ksekar
-<rdar://problem/3831228> Clean up LLQ sleep/wake, error handling
+Revision 1.334 2007/04/19 23:21:51 cheshire
+Fixed a couple of places where the StartGetZoneData check was backwards
-Revision 1.93 2004/10/08 04:17:25 ksekar
-<rdar://problem/3831819> Don't use DNS extensions if the server does not advertise required SRV record
+Revision 1.333 2007/04/19 22:50:53 cheshire
+<rdar://problem/4246187> Identical client queries should reference a single shared core query
-Revision 1.92 2004/10/08 03:54:35 ksekar
-<rdar://problem/3831802> Refine unicast polling intervals
+Revision 1.332 2007/04/19 20:34:32 cheshire
+Add debugging log message in uDNS_CheckQuery()
-Revision 1.91 2004/09/30 17:45:34 ksekar
-<rdar://problem/3821119> lots of log messages: mDNS_SetPrimaryIP: IP address unchanged
+Revision 1.331 2007/04/19 20:06:41 cheshire
+Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
-Revision 1.90 2004/09/25 00:22:13 ksekar
-<rdar://problem/3815534> Crash in uDNS_RegisterService
+Revision 1.330 2007/04/19 19:51:54 cheshire
+Get rid of unnecessary initializeQuery() routine
-Revision 1.89 2004/09/24 19:14:53 cheshire
-Remove unused "extern mDNS mDNSStorage"
+Revision 1.329 2007/04/19 18:03:52 cheshire
+Improved "mDNS_AddSearchDomain" log message
-Revision 1.88 2004/09/23 20:48:15 ksekar
-Clarify retransmission debugf messages.
+Revision 1.328 2007/04/18 20:57:20 cheshire
+Commented out "GetAuthInfoForName none found" debugging message
-Revision 1.87 2004/09/22 00:41:59 cheshire
-Move tcp connection status codes into the legal range allocated for mDNS use
+Revision 1.327 2007/04/17 19:21:29 cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
-Revision 1.86 2004/09/21 23:40:11 ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+Revision 1.326 2007/04/16 20:49:39 cheshire
+Fix compile errors for mDNSPosix build
-Revision 1.85 2004/09/21 22:38:27 ksekar
-<rdar://problem/3810286> PrimaryIP type uninitialized
+Revision 1.325 2007/04/05 22:55:35 cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-Revision 1.84 2004/09/18 00:30:39 cheshire
-<rdar://problem/3806643> Infinite loop in CheckServiceRegistrations
+Revision 1.324 2007/04/05 20:43:30 cheshire
+Collapse sprawling code onto one line -- this is part of a bigger block of identical
+code that has been copied-and-pasted into six different places in the same file.
+This really needs to be turned into a subroutine.
-Revision 1.83 2004/09/17 00:31:51 cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
+Revision 1.323 2007/04/04 21:48:52 cheshire
+<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-Revision 1.82 2004/09/16 21:36:36 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-Changes to add necessary locking calls around unicast DNS operations
+Revision 1.322 2007/04/03 19:53:06 cheshire
+Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
-Revision 1.81 2004/09/16 02:29:39 cheshire
-Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around
-uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService
+Revision 1.321 2007/04/02 23:44:09 cheshire
+Minor code tidying
-Revision 1.80 2004/09/16 01:58:21 cheshire
-Fix compiler warnings
+Revision 1.320 2007/03/31 01:26:13 cheshire
+Take out GetAuthInfoForName syslog message
-Revision 1.79 2004/09/16 00:24:48 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.319 2007/03/31 01:10:53 cheshire
+Add debugging
-Revision 1.78 2004/09/15 01:16:57 ksekar
-<rdar://problem/3797598> mDNSResponder printing too many messages
+Revision 1.318 2007/03/31 00:17:11 cheshire
+Remove some LogMsgs
-Revision 1.77 2004/09/14 23:27:47 cheshire
-Fix compile errors
+Revision 1.317 2007/03/29 00:09:31 cheshire
+Improve "uDNS_InitLongLivedQuery" log message
-Revision 1.76 2004/09/14 22:22:00 ksekar
-<rdar://problem/3800920> Legacy browses broken against some BIND versions
+Revision 1.316 2007/03/28 21:16:27 cheshire
+Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
-Revision 1.75 2004/09/03 19:23:05 ksekar
-<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+Revision 1.315 2007/03/28 21:02:18 cheshire
+<rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
-Revision 1.74 2004/09/02 17:49:04 ksekar
-<rdar://problem/3785135>: 8A246: mDNSResponder crash while logging on restart
-Fixed incorrect conversions, changed %s to %##s for all domain names.
+Revision 1.314 2007/03/28 15:56:37 cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-Revision 1.73 2004/09/02 01:39:40 cheshire
-For better readability, follow consistent convention that QR bit comes first, followed by OP bits
+Revision 1.313 2007/03/28 01:27:32 cheshire
+<rdar://problem/4996439> Unicast DNS polling server every three seconds
+StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
-Revision 1.72 2004/09/01 03:59:29 ksekar
-<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
+Revision 1.312 2007/03/27 23:48:21 cheshire
+Use mDNS_StopGetDomains(), not mDNS_StopQuery()
-Revision 1.71 2004/08/27 17:51:53 ksekar
-Replaced unnecessary LogMsg with debugf.
+Revision 1.311 2007/03/27 22:47:51 cheshire
+Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
-Revision 1.70 2004/08/25 00:37:27 ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+Revision 1.310 2007/03/24 01:24:13 cheshire
+Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
-Revision 1.69 2004/08/18 17:35:41 ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+Revision 1.309 2007/03/24 00:47:53 cheshire
+<rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
+Locking in this file is all messed up. For now we'll just work around the issue.
-Revision 1.68 2004/08/14 03:22:41 cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.308 2007/03/24 00:41:33 cheshire
+Minor code cleanup (move variable declarations to minimum enclosing scope)
-Revision 1.67 2004/08/13 23:46:58 cheshire
-"asyncronous" -> "asynchronous"
+Revision 1.307 2007/03/21 23:06:00 cheshire
+Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
-Revision 1.66 2004/08/13 23:37:02 cheshire
-Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with
-"uDNS_info.UnicastHostname" for clarity
+Revision 1.306 2007/03/21 00:30:03 cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
-Revision 1.65 2004/08/13 23:12:32 cheshire
-Don't use strcpy() and strlen() on "struct domainname" objects;
-use AssignDomainName() and DomainNameLength() instead
-(A "struct domainname" is a collection of packed pascal strings, not a C string.)
+Revision 1.305 2007/03/20 17:07:15 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-Revision 1.64 2004/08/13 23:01:05 cheshire
-Use platform-independent mDNSNULL instead of NULL
+Revision 1.304 2007/03/17 00:02:11 cheshire
+<rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
-Revision 1.63 2004/08/12 00:32:36 ksekar
-<rdar://problem/3759567>: LLQ Refreshes never terminate if unanswered
+Revision 1.303 2007/03/10 03:26:44 cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Revision 1.62 2004/08/10 23:19:14 ksekar
-<rdar://problem/3722542>: DNS Extension daemon for Wide Area Service Discovery
-Moved routines/constants to allow extern access for garbage collection daemon
+Revision 1.302 2007/03/10 02:29:58 cheshire
+Added comments about NAT-PMP response functions
-Revision 1.61 2004/07/30 17:40:06 ksekar
-<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+Revision 1.301 2007/03/10 02:02:58 cheshire
+<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
+Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
-Revision 1.60 2004/07/29 19:40:05 ksekar
-NAT-PMP Support - minor fixes and cleanup
+Revision 1.300 2007/03/08 18:56:00 cheshire
+Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
-Revision 1.59 2004/07/29 19:27:15 ksekar
-NAT-PMP Support - minor fixes and cleanup
+Revision 1.299 2007/02/28 01:45:47 cheshire
+<rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-Revision 1.58 2004/07/27 07:35:38 shersche
-fix syntax error, variables declared in the middle of a block
+Revision 1.298 2007/02/14 03:16:39 cheshire
+<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
-Revision 1.57 2004/07/26 22:49:30 ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.297 2007/02/08 21:12:28 cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-Revision 1.56 2004/07/26 19:14:44 ksekar
-<rdar://problem/3737814>: 8A210: mDNSResponder crashed in startLLQHandshakeCallback
+Revision 1.296 2007/01/29 16:03:22 cheshire
+Fix unused parameter warning
-Revision 1.55 2004/07/15 19:01:33 ksekar
-<rdar://problem/3681029>: Check for incorrect time comparisons
+Revision 1.295 2007/01/27 03:34:27 cheshire
+Made GetZoneData use standard queries (and cached results);
+eliminated GetZoneData_Callback() packet response handler
-Revision 1.54 2004/06/22 02:10:53 ksekar
-<rdar://problem/3705433>: Lighthouse failure causes packet flood to DNS
+Revision 1.294 2007/01/25 00:40:16 cheshire
+Unified CNAME-following functionality into cache management code (which means CNAME-following
+should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
-Revision 1.53 2004/06/17 20:49:09 ksekar
-<rdar://problem/3690436>: mDNSResponder crash while location cycling
+Revision 1.293 2007/01/23 02:56:11 cheshire
+Store negative results in the cache, instead of generating them out of pktResponseHndlr()
-Revision 1.52 2004/06/17 01:13:11 ksekar
-<rdar://problem/3696616>: polling interval too short
+Revision 1.292 2007/01/20 01:32:40 cheshire
+Update comments and debugging messages
-Revision 1.51 2004/06/10 04:36:44 cheshire
-Fix compiler warning
+Revision 1.291 2007/01/20 00:07:02 cheshire
+When we have credentials in the keychain for a domain, we attempt private queries, but
+if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
+or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
-Revision 1.50 2004/06/10 00:55:13 ksekar
-<rdar://problem/3686213>: crash on network reconnect
+Revision 1.290 2007/01/19 23:41:45 cheshire
+Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
-Revision 1.49 2004/06/10 00:10:50 ksekar
-<rdar://problem/3686174>: Infinite Loop in uDNS_Execute()
+Revision 1.289 2007/01/19 23:32:07 cheshire
+Eliminate pointless timenow variable
-Revision 1.48 2004/06/09 20:03:37 ksekar
-<rdar://problem/3686163>: Incorrect copying of resource record in deregistration
+Revision 1.288 2007/01/19 23:26:08 cheshire
+Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
-Revision 1.47 2004/06/09 03:48:28 ksekar
-<rdar://problem/3685226>: nameserver address fails with prod. Lighthouse server
+Revision 1.287 2007/01/19 22:55:41 cheshire
+Eliminate redundant identical parameters to GetZoneData_StartQuery()
-Revision 1.46 2004/06/09 01:44:30 ksekar
-<rdar://problem/3681378> reworked Cache Record copy code
+Revision 1.286 2007/01/19 21:17:33 cheshire
+StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
-Revision 1.45 2004/06/08 18:54:47 ksekar
-<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
+Revision 1.285 2007/01/19 18:39:11 cheshire
+Fix a bunch of parameters that should have been declared "const"
-Revision 1.44 2004/06/05 00:33:51 cheshire
-<rdar://problem/3681029>: Check for incorrect time comparisons
+Revision 1.284 2007/01/19 18:28:28 cheshire
+Improved debugging messages
-Revision 1.43 2004/06/05 00:14:44 cheshire
-Fix signed/unsigned and other compiler warnings
+Revision 1.283 2007/01/19 18:09:33 cheshire
+Fixed getLLQAtIndex (now called GetLLQOptData):
+1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
+2. It used inefficient memory copying instead of just returning a pointer
-Revision 1.42 2004/06/04 22:36:16 ksekar
-Properly set u->nextevent in uDNS_Execute
+Revision 1.282 2007/01/17 22:06:01 cheshire
+Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
-Revision 1.41 2004/06/04 08:58:29 ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
+Revision 1.281 2007/01/17 21:58:13 cheshire
+For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
-Revision 1.40 2004/06/03 03:09:58 ksekar
-<rdar://problem/3668626>: Garbage Collection for Dynamic Updates
+Revision 1.280 2007/01/17 21:46:02 cheshire
+Remove redundant duplicated "isPrivate" field from LLQ_Info
-Revision 1.39 2004/06/01 23:46:50 ksekar
-<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+Revision 1.279 2007/01/17 21:35:31 cheshire
+For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
-Revision 1.38 2004/05/31 22:19:44 ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on
-record changes (#7805) - revert to polling mode on setup errors
+Revision 1.278 2007/01/16 03:04:16 cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
+Don't cache result of ntaContextSRV(context) in a local variable --
+the macro evaluates to a different result after we clear "context->isPrivate"
-Revision 1.37 2004/05/28 23:42:37 ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.277 2007/01/10 22:51:58 cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-Revision 1.36 2004/05/18 23:51:25 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.276 2007/01/10 02:09:30 cheshire
+Better LogOperation record of keys read from System Keychain
-Revision 1.35 2004/05/07 23:01:04 ksekar
-Cleaned up list traversal in deriveGoodbyes - removed unnecessary
-conditional assignment.
+Revision 1.275 2007/01/09 22:37:18 cheshire
+Provide ten-second grace period for deleted keys, to give mDNSResponder
+time to delete host name before it gives up access to the required key.
-Revision 1.34 2004/05/05 18:26:12 ksekar
-Periodically re-transmit questions if the send() fails. Include
-internal questions in retransmission.
+Revision 1.274 2007/01/09 01:16:32 cheshire
+Improve "ERROR m->CurrentQuestion already set" debugging messages
-Revision 1.33 2004/05/05 17:40:06 ksekar
-Removed prerequisite from deregistration update - it does not work for
-shared records, and is unnecessary until we have more sophisticated
-name conflict management.
+Revision 1.273 2007/01/08 23:58:00 cheshire
+Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
-Revision 1.32 2004/05/05 17:32:18 ksekar
-Prevent registration of loopback interface caused by removal of
-Multicast flag in interface structure.
+Revision 1.272 2007/01/05 08:30:42 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.31 2004/05/05 17:05:02 ksekar
-Use LargeCacheRecord structs when pulling records off packets
+Revision 1.271 2007/01/05 06:34:03 cheshire
+Improve "ERROR m->CurrentQuestion already set" debugging messages
-Revision 1.30 2004/04/16 21:33:27 ksekar
-Fixed bug in processing GetZoneData responses that do not use BIND formatting.
+Revision 1.270 2007/01/05 05:44:33 cheshire
+Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
+so that mDNSPosix embedded clients will compile again
-Revision 1.29 2004/04/15 20:03:13 ksekar
-Clarified log message when pulling bad resource records off packet.
+Revision 1.269 2007/01/04 23:11:13 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-Revision 1.28 2004/04/15 00:51:28 bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
+Revision 1.268 2007/01/04 22:06:38 cheshire
+Fixed crash in LLQNatMapComplete()
-Revision 1.27 2004/04/14 23:09:28 ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.267 2007/01/04 21:45:20 cheshire
+Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
+to do additional lock sanity checking around callback invocations
-Revision 1.26 2004/04/14 19:36:05 ksekar
-Fixed memory corruption error in deriveGoodbyes.
+Revision 1.266 2007/01/04 21:01:20 cheshire
+<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
+Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
-Revision 1.25 2004/04/14 04:07:11 ksekar
-Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine.
+Revision 1.265 2007/01/04 20:47:17 cheshire
+Fixed crash in CheckForUnreferencedLLQMapping()
-Revision 1.24 2004/04/08 09:41:40 bradley
-Added const to AuthRecord in deadvertiseIfCallback to match callback typedef.
+Revision 1.264 2007/01/04 20:39:27 cheshire
+Fix locking mismatch
-Revision 1.23 2004/03/24 00:29:45 ksekar
-Make it safe to call StopQuery in a unicast question callback
+Revision 1.263 2007/01/04 02:39:53 cheshire
+<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
-Revision 1.22 2004/03/19 10:11:09 bradley
-Added AuthRecord * cast from umalloc for C++ builds.
+Revision 1.262 2007/01/04 00:29:25 cheshire
+Covert LogMsg() in GetAuthInfoForName to LogOperation()
-Revision 1.21 2004/03/15 02:03:45 bradley
-Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead
-of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++.
+Revision 1.261 2006/12/22 20:59:49 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.20 2004/03/13 02:07:26 ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.260 2006/12/21 00:06:07 cheshire
+Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
-Revision 1.19 2004/03/13 01:57:33 ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.259 2006/12/20 04:07:36 cheshire
+Remove uDNS_info substructure from AuthRecord_struct
-Revision 1.18 2004/02/21 08:34:15 bradley
-Added casts from void * to specific type for C++ builds. Changed void * l-value cast
-r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error.
+Revision 1.258 2006/12/19 22:49:24 cheshire
+Remove uDNS_info substructure from ServiceRecordSet_struct
-Revision 1.17 2004/02/21 02:06:24 cheshire
-Can't use anonymous unions -- they're non-standard and don't work on all compilers
+Revision 1.257 2006/12/19 02:38:20 cheshire
+Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
-Revision 1.16 2004/02/12 01:51:45 cheshire
-Don't try to send uDNS queries unless we have at least one uDNS server available
+Revision 1.256 2006/12/19 02:18:48 cheshire
+Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
-Revision 1.15 2004/02/10 03:02:46 cheshire
-Fix compiler warning
+Revision 1.255 2006/12/16 01:58:31 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
-Revision 1.14 2004/02/06 23:04:19 ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.254 2006/12/15 19:23:39 cheshire
+Use new DomainNameLengthLimit() function, to be more defensive against malformed
+data received from the network.
-Revision 1.13 2004/02/03 22:15:01 ksekar
-Fixed nameToAddr error check: don't abort state machine on nxdomain error.
+Revision 1.253 2006/12/01 07:43:34 herscher
+Fix byte ordering problem for one-shot TCP queries.
+Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
-Revision 1.12 2004/02/03 19:47:36 ksekar
-Added an asynchronous state machine mechanism to uDNS.c, including
-calls to find the parent zone for a domain name. Changes include code
-in repository previously dissabled via "#if 0 incomplete". Codepath
-is currently unused, and will be called to create update records, etc.
+Revision 1.252 2006/11/30 23:07:57 herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-Revision 1.11 2004/01/30 02:12:30 ksekar
-Changed uDNS_ReceiveMsg() to correctly return void.
+Revision 1.251 2006/11/28 21:42:11 mkrochma
+Work around a crashing bug that was introduced by uDNS and mDNS code unification
-Revision 1.10 2004/01/29 02:59:17 ksekar
-Unicast DNS: Changed from a resource record oriented question/response
-matching to packet based matching. New callback architecture allows
-collections of records in a response to be processed differently
-depending on the nature of the request, and allows the same structure
-to be used for internal and client-driven queries with different processing needs.
+Revision 1.250 2006/11/18 05:01:30 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
-Revision 1.9 2004/01/28 20:20:45 ksekar
-Unified ActiveQueries and ActiveInternalQueries lists, using a flag to
-demux them. Check-in includes work-in-progress code, #ifdef'd out.
+Revision 1.249 2006/11/10 07:44:04 herscher
+<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-Revision 1.8 2004/01/28 02:30:07 ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane. Stopped sending unicast messages on
-every interface. Fixed unicast resolving via mach-port API.
+Revision 1.248 2006/11/08 04:26:53 cheshire
+Fix typo in debugging message
-Revision 1.7 2004/01/27 20:15:22 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.247 2006/10/20 05:35:04 herscher
+<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-Revision 1.6 2004/01/24 23:47:17 cheshire
-Use mDNSOpaque16fromIntVal() instead of shifting and masking
+Revision 1.246 2006/10/11 19:29:41 herscher
+<rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
-Revision 1.5 2004/01/24 04:59:15 cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.245 2006/10/04 22:21:15 herscher
+Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
-Revision 1.4 2004/01/24 04:19:26 cheshire
-Restore overwritten checkin 1.2
+Revision 1.244 2006/10/04 21:51:27 herscher
+Replace calls to mDNSPlatformTimeNow(m) with m->timenow
-Revision 1.3 2004/01/23 23:23:15 ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.243 2006/10/04 21:38:59 herscher
+Remove uDNS_info substructure from DNSQuestion_struct
-Revision 1.2 2004/01/22 03:48:41 cheshire
-Make sure uDNS client doesn't accidentally use query ID zero
+Revision 1.242 2006/09/27 00:51:46 herscher
+Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
-Revision 1.1 2003/12/13 03:05:27 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.241 2006/09/26 01:54:47 herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
- */
+Revision 1.240 2006/09/15 21:20:15 cheshire
+Remove uDNS_info substructure from mDNS_struct
+
+Revision 1.239 2006/08/16 02:52:56 mkrochma
+<rdar://problem/4104154> Actually fix it this time
+
+Revision 1.238 2006/08/16 00:31:50 mkrochma
+<rdar://problem/4386944> Get rid of NotAnInteger references
+
+Revision 1.237 2006/08/15 23:38:17 mkrochma
+<rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion
+
+Revision 1.236 2006/08/14 23:24:23 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.235 2006/07/30 05:45:36 cheshire
+<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
+
+Revision 1.234 2006/07/22 02:58:36 cheshire
+Code was clearing namehash twice instead of namehash and rdatahash
+
+Revision 1.233 2006/07/20 19:46:51 mkrochma
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix Private DNS
+
+Revision 1.232 2006/07/15 02:01:29 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
+
+Revision 1.231 2006/07/05 23:28:22 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+
+Revision 1.230 2006/06/29 03:02:44 cheshire
+<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
+
+Revision 1.229 2006/03/02 22:03:41 cheshire
+<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
+Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
+
+Revision 1.228 2006/02/26 00:54:42 cheshire
+Fixes to avoid code generation warning/error on FreeBSD 7
+
+Revision 1.227 2006/01/09 20:47:05 cheshire
+<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
+
+*/
#include "uDNS.h"
#pragma warning(disable:4706)
#endif
-#define umalloc(x) mDNSPlatformMemAllocate(x) // short hands for common routines
-#define ufree(x) mDNSPlatformMemFree(x)
-#define ubzero(x,y) mDNSPlatformMemZero(x,y)
-#define umemcpy(x, y, l) mDNSPlatformMemCopy(y, x, l) // uses memcpy(2) arg ordering
-
-// Asynchronous operation types
-
-typedef enum
+typedef struct tcpInfo_t
{
- zoneDataResult
- // other async. operation names go here
- } AsyncOpResultType;
-
-typedef struct
- {
- domainname zoneName;
- mDNSAddr primaryAddr;
- mDNSu16 zoneClass;
- mDNSIPPort llqPort;
- mDNSIPPort updatePort;
- } zoneData_t;
-
-// other async. result struct defs go here
-
-typedef struct
- {
- AsyncOpResultType type;
- zoneData_t zoneData;
- // other async result structs go here
- } AsyncOpResult;
-
-typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
-
-
-// Private Function Prototypes
-// Note: In general, functions are ordered such that they do not require forward declarations.
-// However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls
-// foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
-// read top-to-bottom.)
-
-mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n);
-mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m);
-mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo);
-mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
-mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr);
-mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
-mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs);
-mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result);
-mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive);
-mDNSlocal void RestartQueries(mDNS *m);
-mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer);
-mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context);
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Temporary workaround
-#endif
-
-// 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe
-// The platform function is now called mDNSPlatformRawTime(), and
-// mDNSPlatformTimeNow() is defined here as a temporary workaround.
-// This is a gross hack, and after this change has been tested for a while,
-// all these calls should be replaced by simple references to m->timenow
+ mDNS *m;
+ TCPSocket *sock;
+ DNSMessage request;
+ int requestLen;
+ DNSQuestion *question; // For queries
+ ServiceRecordSet *srs; // For service record updates
+ AuthRecord *rr; // For record updates
+ mDNSAddr Addr;
+ mDNSIPPort Port;
+ DNSMessage *reply;
+ mDNSu16 replylen;
+ unsigned long nread;
+ int numReplies;
+ } tcpInfo_t;
-mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m)
+typedef struct SearchListElem
{
- if (m->mDNS_busy && m->timenow) return(m->timenow);
- LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock");
-
- // To get a quick and easy stack trace to find out *how* this routine
- // is being called without holding main mDNS lock, uncomment the line below:
- // *(long*)0=0;
-
- return(mDNS_TimeNow(m));
- }
+ struct SearchListElem *next;
+ domainname domain;
+ int flag; // -1 means delete, 0 means unchanged, +1 means newly added
+ DNSQuestion BrowseQ;
+ DNSQuestion DefBrowseQ;
+ DNSQuestion AutomaticBrowseQ;
+ DNSQuestion RegisterQ;
+ DNSQuestion DefRegisterQ;
+ ARListElem *AuthRecs;
+ } SearchListElem;
+
+// For domain enumeration and automatic browsing
+// This is the user's DNS search list.
+// In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
+// to discover recommended domains for domain enumeration (browse, default browse, registration,
+// default registration) and possibly one or more recommended automatic browsing domains.
+static SearchListElem *SearchList = mDNSNULL;
+
+// Temporary workaround to make ServiceRecordSet list management safe.
+// Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
+// -- it should just be a grouping of records that are treated the same as any other registered records.
+// In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
+// would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
+static ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - General Utility Functions
#endif
-// CountLabels() returns number of labels in name, excluding final root label
-// (e.g. for "apple.com." CountLabels returns 2.)
-mDNSlocal int CountLabels(const domainname *d)
- {
- int count = 0;
- const mDNSu8 *ptr;
-
- for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
- return count;
- }
-
-mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
- {
- static mDNSBool randomized = mDNSfalse;
-
- if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
- if (u->NextMessageID == 0) u->NextMessageID++;
- return mDNSOpaque16fromIntVal(u->NextMessageID++);
- }
-
-// unlink an AuthRecord from a linked list
-mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
+// Unlink an AuthRecord from the m->ResourceRecords list.
+// This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
+// remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
+mDNSlocal mStatus UnlinkAuthRecord(mDNS *const m, AuthRecord *const rr)
{
+ AuthRecord **list = &m->ResourceRecords;
+ if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
+ if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
while (*list && *list != rr) list = &(*list)->next;
+ if (!*list)
+ {
+ list = &m->DuplicateRecords;
+ while (*list && *list != rr) list = &(*list)->next;
+ }
if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); }
- LogMsg("ERROR: unlinkAR - no such active record %##s", rr->resrec.name->c);
+ LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr->resrec.name->c);
return(mStatus_NoSuchRecord);
}
-mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs)
+// unlinkSRS is an internal routine (i.e. must be called with the lock already held)
+mDNSlocal void unlinkSRS(mDNS *const m, ServiceRecordSet *srs)
{
- uDNS_GlobalInfo *u = &m->uDNS_info;
ServiceRecordSet **p;
- NATTraversalInfo *n = u->NATTraversals;
- // verify that no NAT objects reference this service
- while (n)
+ if (srs->NATinfo.clientContext)
{
- if (n->reg.ServiceRegistration == srs)
- {
- NATTraversalInfo *tmp = n;
- n = n->next;
- LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c);
- FreeNATInfo(m, tmp);
- }
- else n = n->next;
+ mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+ srs->NATinfo.clientContext = mDNSNULL;
}
-
- for (p = &u->ServiceRegistrations; *p; p = &(*p)->next)
+
+ for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next)
if (*p == srs)
{
ExtraResourceRecord *e;
- *p = srs->next;
- srs->next = mDNSNULL;
+ *p = srs->uDNS_next;
+ if (CurrentServiceRecordSet == srs)
+ CurrentServiceRecordSet = srs->uDNS_next;
+ srs->uDNS_next = mDNSNULL;
for (e=srs->Extras; e; e=e->next)
- if (unlinkAR(&u->RecordRegistrations, &e->r))
+ if (UnlinkAuthRecord(m, &e->r))
LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c);
return;
}
LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
}
-mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q)
- {
- if (uDNS_IsActiveQuery(q, u))
- { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; }
-
- q->next = u->ActiveQueries;
- u->ActiveQueries = q;
- }
-
// set retry timestamp for record with exponential backoff
// (for service record sets, use RR_SRV as representative for time checks
mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
{
- rr->LastAPTime = mDNSPlatformTimeNow(m);
+ rr->LastAPTime = m->timenow;
if (SendErr == mStatus_TransientErr || rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL) rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
else if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL) rr->ThisAPInterval *= 2;
- else if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL) rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL;
+ else rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL;
}
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - Name Server List Management
#endif
-mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- DNSServer *s, **p = &u->Servers;
-
- mDNS_Lock(m);
- if (!d) d = (domainname *)"";
+mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
+ {
+ DNSServer **p = &m->DNSServers;
+
+ if (!d) d = (const domainname *)"";
+
+ LogOperation("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c);
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
- while (*p) // Check if we already have this {server,domain} pair registered
+ while (*p) // Check if we already have this {server,domain} pair registered
{
- if (mDNSSameAddress(&(*p)->addr, addr) && SameDomainName(&(*p)->domain, d))
- LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
+ if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
+ mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
+ {
+ if (!(*p)->del) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c);
+ (*p)->del = mDNSfalse;
+ return(*p);
+ }
p=&(*p)->next;
}
// allocate, add to list
- s = umalloc(sizeof(*s));
- if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
- s->addr = *addr;
- s->del = mDNSfalse;
- s->teststate = DNSServer_Untested;
- AssignDomainName(&s->domain, d);
- s->next = mDNSNULL;
- *p = s;
-
- end:
- mDNS_Unlock(m);
- }
-
-mDNSexport void mDNS_DeleteDNSServers(mDNS *const m)
- {
- DNSServer *s;
- mDNS_Lock(m);
-
- s = m->uDNS_info.Servers;
- m->uDNS_info.Servers = mDNSNULL;
- while (s)
+ *p = mDNSPlatformMemAllocate(sizeof(**p));
+ if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
+ else
{
- DNSServer *tmp = s;
- s = s->next;
- ufree(tmp);
+ (*p)->interface = interface;
+ (*p)->addr = *addr;
+ (*p)->port = port;
+ (*p)->del = mDNSfalse;
+ (*p)->teststate = DNSServer_Untested;
+ (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL;
+ AssignDomainName(&(*p)->domain, d);
+ (*p)->next = mDNSNULL;
}
+ return(*p);
+ }
- mDNS_Unlock(m);
- }
-
- // ***************************************************************************
+// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - authorization management
#endif
-mDNSlocal uDNS_AuthInfo *GetAuthInfoForName(const uDNS_GlobalInfo *u, const domainname *name)
+mDNSlocal DomainAuthInfo *GetAuthInfoForName_direct(mDNS *m, const domainname *const name)
{
- uDNS_AuthInfo *ptr;
- while (name->c[0])
+ const domainname *n = name;
+ while (n->c[0])
{
- for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
- if (SameDomainName(&ptr->zone, name)) return(ptr);
- name = (const domainname *)(name->c + 1 + name->c[0]);
+ DomainAuthInfo *ptr;
+ for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+ if (SameDomainName(&ptr->domain, n))
+ {
+ debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name->c, ptr->domain.c, ptr->keyname.c);
+ return(ptr);
+ }
+ n = (const domainname *)(n->c + 1 + n->c[0]);
}
+ //LogOperation("GetAuthInfoForName none found for %##s", name->c);
return mDNSNULL;
}
-mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
+// MUST be called with lock held
+mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name)
{
- uDNS_AuthInfo *ptr, *prev = mDNSNULL;
+ DomainAuthInfo **p = &m->AuthInfoList;
+
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
- for (ptr = u->AuthInfoList; ptr; ptr = ptr->next)
+ // First purge any dead keys from the list
+ while (*p)
{
- if (SameDomainName(&ptr->zone, zone))
+ if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
{
- if (prev) prev->next = ptr->next;
- else u->AuthInfoList = ptr->next;
- ufree(ptr);
- return;
+ DNSQuestion *q;
+ DomainAuthInfo *info = *p;
+ LogOperation("GetAuthInfoForName_internal deleting expired key %##s %##s", info->domain.c, info->keyname.c);
+ *p = info->next; // Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers
+ for (q = m->Questions; q; q=q->next)
+ if (q->AuthInfo == info)
+ {
+ q->AuthInfo = GetAuthInfoForName_direct(m, &q->qname);
+ debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)",
+ info->domain.c, q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
+ }
+
+ // Probably not essential, but just to be safe, zero out the secret key data
+ // so we don't leave it hanging around in memory
+ // (where it could potentially get exposed via some other bug)
+ mDNSPlatformMemZero(info, sizeof(*info));
+ mDNSPlatformMemFree(info);
}
- prev = ptr;
+ else
+ p = &(*p)->next;
}
+
+ return(GetAuthInfoForName_direct(m, name));
}
-mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret)
+mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name)
{
- uDNS_AuthInfo *info;
- mDNSu8 keybuf[1024];
- mDNSs32 keylen;
- uDNS_GlobalInfo *u = &m->uDNS_info;
- mStatus status = mStatus_NoError;
-
+ DomainAuthInfo *d;
mDNS_Lock(m);
-
- if (GetAuthInfoForName(u, zone)) DeleteAuthInfoForZone(u, zone);
- if (!key) goto exit;
-
- info = (uDNS_AuthInfo*)umalloc(sizeof(*info));
- if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; }
- ubzero(info, sizeof(*info));
- AssignDomainName(&info->zone, zone);
- AssignDomainName(&info->keyname, key);
-
- keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024);
- if (keylen < 0)
- {
- LogMsg("ERROR: mDNS_SetSecretForZone - could not convert shared secret %s from base64", sharedSecret);
- ufree(info);
- status = mStatus_UnknownErr;
- goto exit;
- }
- DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
-
- // link into list
- info->next = m->uDNS_info.AuthInfoList;
- m->uDNS_info.AuthInfoList = info;
-exit:
+ d = GetAuthInfoForName_internal(m, name);
mDNS_Unlock(m);
- return status;
+ return(d);
}
-
- // ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - NAT Traversal
-#endif
-mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
+// MUST be called with the lock held
+mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
+ const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
{
- const domainlabel *l;
- domainlabel buf;
-
- if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse;
-
- for (l = (const domainlabel *)d; l->c[0]; l = (const domainlabel *)(l->c + l->c[0]+1))
- if (SameDomainLabel(l->c, buf.c)) return mDNStrue;
- return mDNSfalse;
- }
+ DNSQuestion *q;
+ DomainAuthInfo **p = &m->AuthInfoList;
+ if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
-// allocate struct, link into global list, initialize
-mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- NATTraversalInfo *info = umalloc(sizeof(NATTraversalInfo));
- if (!info) { LogMsg("ERROR: malloc"); return mDNSNULL; }
- ubzero(info, sizeof(NATTraversalInfo));
- info->next = u->NATTraversals;
- u->NATTraversals = info;
- info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
- info->op = op;
- info->state = NATState_Init;
- info->ReceiveResponse = callback;
- info->PublicPort.NotAnInteger = 0;
- info->Router = u->Router;
- return info;
- }
+ LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : "");
-// unlink from list, deallocate
-mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
- {
- NATTraversalInfo *ptr, *prev = mDNSNULL;
- ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
+ info->AutoTunnel = AutoTunnel;
+ AssignDomainName(&info->domain, domain);
+ AssignDomainName(&info->keyname, keyname);
+ mDNS_snprintf(info->b64keydata, sizeof(info->b64keydata), "%s", b64keydata);
- // Verify that object is not referenced by any services
- while (s)
+ if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0)
{
- if (s->uDNS_info.NATinfo == n)
- {
- LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s->RR_SRV.resrec.name->c);
- s->uDNS_info.NATinfo = mDNSNULL;
- }
- s = s->next;
+ LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s",
+ domain->c, keyname->c, LogAllOperations ? b64keydata : "");
+ return(mStatus_BadParamErr);
}
-
- if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
- ptr = m->uDNS_info.NATTraversals;
- while (ptr)
+
+ // Don't clear deltime until after we've ascertained that b64keydata is valid
+ info->deltime = 0;
+
+ while (*p && (*p) != info) p=&(*p)->next;
+ if (*p) return(mStatus_AlreadyRegistered);
+
+ // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
+ // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
+ info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnelHostRecord.namestorage.c[0] = 0;
+ info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered;
+ info->AutoTunnelNAT.clientContext = mDNSNULL;
+ info->next = mDNSNULL;
+ *p = info;
+
+ // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions
+ for (q = m->Questions; q; q=q->next)
{
- if (ptr == n)
+ if (q->QuestionCallback != GetZoneData_QuestionCallback)
{
- if (prev) prev->next = ptr->next;
- else m->uDNS_info.NATTraversals = ptr->next;
- ufree(n);
- return mDNStrue;
+ DomainAuthInfo *newinfo = GetAuthInfoForName_internal(m, &q->qname);
+ if (q->AuthInfo != newinfo)
+ {
+ debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)",
+ q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL,
+ newinfo ? newinfo ->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype));
+ q->AuthInfo = newinfo;
+ }
}
- prev = ptr;
- ptr = ptr->next;
}
- LogMsg("FreeNATInfo: NATTraversalInfo not found in list");
- return mDNSfalse;
+
+ return(mStatus_NoError);
}
-mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
- {
- mStatus err;
- mDNSAddr dst;
- mDNSIPPort dstport;
- uDNS_GlobalInfo *u = &m->uDNS_info;
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - NAT Traversal
+#endif
- if (info->state != NATState_Request && info->state != NATState_Refresh)
- { LogMsg("SendNATMsg: Bad state %d", info->state); return; }
+mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info)
+ {
+ mStatus err = mStatus_NoError;
- if (u->Router.ip.v4.NotAnInteger)
+ // send msg if we have a router and it is a private address
+ if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSv4AddrIsRFC1918(&m->Router.ip.v4))
{
- // send msg if we have a router
- const mDNSu8 *end = (mDNSu8 *)&info->request;
- if (info->op == NATOp_AddrRequest) end += sizeof(NATAddrRequest);
- else end += sizeof(NATPortMapRequest);
+ union { NATAddrRequest NATAddrReq; NATPortMapRequest NATPortReq; } u = { { NATMAP_VERS, NATOp_AddrRequest } } ;
+ const mDNSu8 *end = (mDNSu8 *)&u + sizeof(NATAddrRequest);
+
+ if (info) // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields
+ {
+ mDNSu8 *p = (mDNSu8 *)&u.NATPortReq.NATReq_lease;
+ u.NATPortReq.opcode = info->Protocol;
+ u.NATPortReq.unused = zeroID;
+ u.NATPortReq.intport = info->IntPort;
+ u.NATPortReq.extport = info->RequestedPort;
+ p[0] = (mDNSu8)((info->NATLease >> 24) & 0xFF);
+ p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF);
+ p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF);
+ p[3] = (mDNSu8)( info->NATLease & 0xFF);
+ end = (mDNSu8 *)&u + sizeof(NATPortMapRequest);
+ }
+
+ err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, &m->Router, NATPMPPort);
- dst.type = u->Router.type;
- dst.ip.v4 = u->Router.ip.v4;
- dstport = mDNSOpaque16fromIntVal(NATMAP_PORT);
- err = mDNSPlatformSendUDP(m, &info->request, end, 0, &dst, dstport);
- if (!err) (info->ntries++); // don't increment attempt counter if the send failed
+#ifdef _LEGACY_NAT_TRAVERSAL_
+ if (mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m);
+ else if (info) err = LNT_MapPort(m, info);
+ else err = LNT_GetExternalAddress(m);
+#endif // _LEGACY_NAT_TRAVERSAL_
}
-
- // set retry
- if (info->RetryInterval < NATMAP_INIT_RETRY) info->RetryInterval = NATMAP_INIT_RETRY;
- else if (info->RetryInterval * 2 > NATMAP_MAX_RETRY) info->RetryInterval = NATMAP_MAX_RETRY;
- else info->RetryInterval *= 2;
- info->retry = mDNSPlatformTimeNow(m) + info->RetryInterval;
+ return(err);
}
-mDNSlocal mDNSBool ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
+mDNSlocal void RecreateNATMappings(mDNS *const m)
{
- mStatus err = mStatus_NoError;
- AuthRecord *rr = mDNSNULL;
- NATAddrReply *response = (NATAddrReply *)pkt;
- mDNSAddr addr;
-
- if (n->state != NATState_Request)
- {
- LogMsg("ReceiveNATAddrResponse: bad state %d", n->state);
- return mDNSfalse;
- }
-
- rr = n->reg.RecordRegistration;
- if (!rr)
+ NATTraversalInfo *n;
+ for (n = m->NATTraversals; n; n=n->next)
{
- LogMsg("ReceiveNATAddrResponse: registration cancelled");
- return mDNSfalse;
+ n->ExpiryTime = 0; // Mark this mapping as expired
+ n->retryInterval = NATMAP_INIT_RETRY;
+ n->retryPortMap = m->timenow;
+#ifdef _LEGACY_NAT_TRAVERSAL_
+ if (n->tcpInfo.sock) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; }
+#endif // _LEGACY_NAT_TRAVERSAL_
}
- addr.type = mDNSAddrType_IPv4;
- addr.ip.v4 = rr->resrec.rdata->u.ipv4;
+ m->NextScheduledNATOp = m->timenow; // Need to send packets immediately
+ }
- if (!pkt) // timeout
- {
#ifdef _LEGACY_NAT_TRAVERSAL_
- err = LNT_GetPublicIP(&addr.ip.v4);
- if (err) goto end;
- else n->state = NATState_Legacy;
+mDNSlocal void ClearUPnPState(mDNS *const m)
+ {
+ if (m->tcpAddrInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock); m->tcpAddrInfo.sock = mDNSNULL; }
+ if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; }
+ m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort; // Reset UPnP ports
+ }
#else
- debugf("ReceiveNATAddrResponse: timeout");
- err = mStatus_NATTraversal;
- goto end;
+#define ClearUPnPState(X)
#endif // _LEGACY_NAT_TRAVERSAL_
- }
- else
- {
- if (len < sizeof(*response))
- {
- LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
- return mDNSfalse;
- }
- if (response->vers != NATMAP_VERS)
- {
- LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt[0], NATMAP_VERS);
- return mDNSfalse;
- }
- if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
- {
- LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode);
- return mDNSfalse;
- }
- if (response->err.NotAnInteger)
- { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; }
- addr.ip.v4 = response->PubAddr;
- n->state = NATState_Established;
- }
-
- if (IsPrivateV4Addr(&addr))
- {
- LogMsg("ReceiveNATAddrResponse: Double NAT");
- err = mStatus_DoubleNAT;
- goto end;
- }
-
- end:
- if (err)
+mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr)
+ {
+ if (err) LogMsg("Error getting external address %d", err);
+ else if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr))
{
- FreeNATInfo(m, n);
- if (rr)
- {
- rr->uDNS_info.NATinfo = mDNSNULL;
- rr->uDNS_info.state = regState_Unregistered; // note that rr is not yet in global list
- rr->RecordCallback(m, rr, mStatus_NATTraversal);
- // note - unsafe to touch rr after callback
- }
- return mDNStrue;
+ LogOperation("Received external IP address %.4a from NAT", &ExtAddr);
+ if (mDNSv4AddrIsRFC1918(&ExtAddr))
+ LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr);
+ m->ExternalAddress = ExtAddr;
+ RecreateNATMappings(m); // Also sets NextScheduledNATOp for us
}
- else LogOperation("Received public IP address %d.%d.%d.%d from NAT.", addr.ip.v4.b[0], addr.ip.v4.b[1], addr.ip.v4.b[2], addr.ip.v4.b[3]);
- rr->resrec.rdata->u.ipv4 = addr.ip.v4; // replace rdata w/ public address
- uDNS_RegisterRecord(m, rr);
- return mDNStrue;
- }
+ if (err || mDNSIPv4AddressIsZero(ExtAddr)) m->retryIntervalGetAddr = NATMAP_INIT_RETRY * 32; // 8 seconds
+ else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
-mDNSlocal void StartGetPublicAddr(mDNS *m, AuthRecord *AddressRec)
- {
- NATAddrRequest *req;
- uDNS_GlobalInfo *u = &m->uDNS_info;
-
- NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse);
- if (!info) { uDNS_RegisterRecord(m, AddressRec); return; }
- AddressRec->uDNS_info.NATinfo = info;
- info->reg.RecordRegistration = AddressRec;
- info->state = NATState_Request;
-
- // format message
- req = &info->request.AddrReq;
- req->vers = NATMAP_VERS;
- req->opcode = NATOp_AddrRequest;
-
- if (!u->Router.ip.v4.NotAnInteger)
- {
- debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY);
- return;
- }
-
- SendNATMsg(info, m);
+ m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
+ if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0)
+ m->NextScheduledNATOp = m->retryIntervalGetAddr;
}
-
-mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m)
+// Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards
+mDNSlocal void NATSetNextRenewalTime(mDNS *const m, NATTraversalInfo *n)
{
- n->state = NATState_Refresh;
- n->RetryInterval = NATMAP_INIT_RETRY;
- n->ntries = 0;
- SendNATMsg(n, m);
+ n->retryInterval = (n->ExpiryTime - m->timenow)/2;
+ if (n->retryInterval < NATMAP_MIN_RETRY_INTERVAL) // Min retry interval is 2 seconds
+ n->retryInterval = NATMAP_MIN_RETRY_INTERVAL;
+ n->retryPortMap = m->timenow + n->retryInterval;
}
-mDNSlocal void LLQNatMapComplete(mDNS *m)
+// Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in
+mDNSexport void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease)
{
- uDNS_GlobalInfo *u = &m->uDNS_info;
- LLQ_Info *llqInfo;
- NATTraversalInfo *n = u->LLQNatInfo;
+ n->NewResult = err;
+ if (err || lease == 0 || mDNSIPPortIsZero(extport))
+ {
+ LogOperation("natTraversalHandlePortMapReply: received error making port mapping error %d port %d", err, mDNSVal16(extport));
+ n->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
+ n->retryPortMap = m->timenow + NATMAP_MAX_RETRY_INTERVAL;
+ // No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time
+ if (err == NATErr_Refused) n->NewResult = mStatus_NATPortMappingDisabled;
+ else if (err > NATErr_None && err <= NATErr_Opcode) n->NewResult = mStatus_NATPortMappingUnsupported;
+ }
+ else
+ {
+ if (lease > 999999999UL / mDNSPlatformOneSecond)
+ lease = 999999999UL / mDNSPlatformOneSecond;
+ n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond);
- if (!n) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; }
- if (n->state != NATState_Established && n->state != NATState_Legacy && n->state != NATState_Error)
- { LogMsg("LLQNatMapComplete - bad nat state %d", n->state); return; }
+ if (!mDNSSameIPPort(n->RequestedPort, extport))
+ LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n->RequestedPort), mDNSVal16(extport));
- u->CurrentQuery = u->ActiveQueries;
- while (u->CurrentQuery)
- {
- DNSQuestion *q = u->CurrentQuery;
- u->CurrentQuery = u->CurrentQuery->next;
- llqInfo = q->uDNS_info.llq;
- if (q->LongLived && llqInfo->state == LLQ_NatMapWait)
- {
- if (n->state == NATState_Error)
- {
- llqInfo->NATMap = mDNSfalse;
- llqInfo->question->uDNS_info.responseCallback = llqResponseHndlr;
- llqInfo->state = LLQ_Poll;
- llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
- llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
- }
- else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }
- }
+ n->InterfaceID = InterfaceID;
+ n->RequestedPort = extport;
+
+ LogOperation("natTraversalHandlePortMapReply %p %s Internal Port %d External Port %d", n,
+ n->Protocol == NATOp_MapUDP ? "UDP Response" :
+ n->Protocol == NATOp_MapTCP ? "TCP Response" : "?", mDNSVal16(n->IntPort), mDNSVal16(n->RequestedPort));
+
+ NATSetNextRenewalTime(m, n); // Got our port mapping; now set timer to renew it at halfway point
+ m->NextScheduledNATOp = m->timenow; // May need to invoke client callback immediately
}
}
-mDNSlocal mDNSBool ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
+// Must be called with the mDNS_Lock held
+mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal)
{
- ServiceRecordSet *srs = n->reg.ServiceRegistration;
- mDNSIPPort priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4;
- mDNSu32 lease;
- mDNSBool deletion = !n->request.PortReq.lease.NotAnInteger;
- NATPortMapReply *reply = (NATPortMapReply *)pkt;
- mDNSu8 *service = srs ? srs->RR_SRV.resrec.name->c : (mDNSu8 *)"\016LLQ event port";
-
- if (n->state != NATState_Request && n->state != NATState_Refresh)
- { LogMsg("ReceivePortMapReply (%##s): bad state %d", service, n->state); return mDNSfalse; }
-
- if (!pkt && !deletion) // timeout
- {
-#ifdef _LEGACY_NAT_TRAVERSAL_
- mDNSIPPort pub;
- int ntries = 0;
- mStatus err;
- mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp"));
-
- pub = priv; // initially request priv == pub
- while (1)
- {
- err = LNT_MapPort(priv, pub, tcp);
- if (!err)
- {
- n->PublicPort = pub;
- n->state = NATState_Legacy;
- goto end;
- }
- else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES)
- {
- n->state = NATState_Error;
- goto end;
- }
- else
- {
- // the mapping we want is taken - try a random port
- mDNSu16 RandPort = mDNSRandom(DYN_PORT_MAX - DYN_PORT_MIN) + DYN_PORT_MIN;
- pub = mDNSOpaque16fromIntVal(RandPort);
- }
- }
-#else
- goto end;
-#endif // _LEGACY_NAT_TRAVERSAL_
- }
+ NATTraversalInfo **n;
+
+ LogOperation("mDNS_StartNATOperation_internal %d %d %d %d",
+ traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
+
+ // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start
+ n = &m->NATTraversals;
+ while (*n && *n != traversal) n=&(*n)->next;
+ if (*n) { LogMsg("Error! Tried to add a NAT traversal that's already in the active list"); return(mStatus_AlreadyRegistered); }
+
+ // Initialize necessary fields
+ traversal->next = mDNSNULL;
+ traversal->ExpiryTime = 0;
+ traversal->retryInterval = NATMAP_INIT_RETRY;
+ traversal->retryPortMap = m->timenow;
+ traversal->NewResult = mStatus_NoError;
+ traversal->ExternalAddress = onesIPv4Addr;
+ traversal->ExternalPort = zeroIPPort;
+ traversal->Lifetime = 0;
+ traversal->Result = mStatus_NoError;
+
+ // set default lease if necessary
+ if (!traversal->NATLease) traversal->NATLease = NATMAP_DEFAULT_LEASE;
- if (len < sizeof(*reply)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); return mDNSfalse; }
- if (reply->vers != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received version %d (expect version %d)", pkt[0], NATMAP_VERS); return mDNSfalse; }
- if (reply->opcode != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); return mDNSfalse; }
- if (reply->err.NotAnInteger) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply->err)); return mDNSfalse; }
- if (priv.NotAnInteger != reply->priv.NotAnInteger) return mDNSfalse; // packet does not match this request
+#ifdef _LEGACY_NAT_TRAVERSAL_
+ mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo));
+#endif _LEGACY_NAT_TRAVERSAL_
- if (!srs && n != m->uDNS_info.LLQNatInfo)
+ if (!m->NATTraversals) // If this is our first NAT request, kick off an address request too
{
- LogMsg("ReceivePortMapReply: registration cancelled"); //!!!KRS change to debugf before checkin
- FreeNATInfo(m, n);
- return mDNStrue;
+ m->retryGetAddr = m->timenow;
+ m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
}
- if (deletion) { n->state = NATState_Deleted; return mDNStrue; }
-
- lease = (mDNSu32)mDNSVal32(reply->lease);
- if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond;
-
- if (n->state == NATState_Refresh && reply->pub.NotAnInteger != n->PublicPort.NotAnInteger)
- LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(reply->pub));
- // this should never happen
- // !!!KRS to be defensive, use SRVChanged flag on service and deregister here
-
- n->PublicPort = reply->pub;
- if (reply->pub.NotAnInteger != n->request.PortReq.pub.NotAnInteger) n->request.PortReq.pub = reply->pub; // set message buffer for refreshes
+ m->NextScheduledNATOp = m->timenow; // This will always trigger sending the packet ASAP, and generate client callback if necessary
- n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2); // retry half way to expiration
+ *n = traversal; // Append new NATTraversalInfo to the end of our list
- if (n->state == NATState_Refresh) { n->state = NATState_Established; return mDNStrue; }
- n->state = NATState_Established;
+ return(mStatus_NoError);
+ }
- end:
- if (n->state != NATState_Established && n->state != NATState_Legacy)
+// Must be called with the mDNS_Lock held
+mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal)
+ {
+ NATTraversalInfo **ptr = &m->NATTraversals;
+
+ while (*ptr && *ptr != traversal) ptr=&(*ptr)->next;
+ if (*ptr) *ptr = (*ptr)->next; // If we found it, cut this NATTraversalInfo struct from our list
+ else
{
- LogMsg("NAT Port Mapping (%##s): timeout", service);
- if (pkt) LogMsg("!!! timeout with non-null packet");
- n->state = NATState_Error;
- if (srs)
- {
- uDNS_HostnameInfo *hi = m->uDNS_info.Hostnames;
- while (hi)
- {
- if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) break;
- else hi = hi->next;
- }
-
- if (hi)
- {
- debugf("Port map failed for service %##s - using IPv6 service target", service);
- srs->uDNS_info.NATinfo = mDNSNULL;
- FreeNATInfo(m, n);
- goto register_service;
- }
- else srs->uDNS_info.state = regState_NATError;
- }
- else LLQNatMapComplete(m);
- return mDNStrue;
+ LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal);
+ return(mStatus_BadReferenceErr);
}
- else LogOperation("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort));
- if (!srs) { LLQNatMapComplete(m); return mDNStrue; }
+ LogOperation("mDNS_StopNATOperation_internal %d %d %d %d",
+ traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
- register_service:
- if (srs->uDNS_info.ns.ip.v4.NotAnInteger) SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update
- else
+ if (m->CurrentNATTraversal == traversal)
+ m->CurrentNATTraversal = m->CurrentNATTraversal->next;
+
+ if (traversal->ExpiryTime)
{
- srs->uDNS_info.state = regState_FetchingZoneData;
- startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+ traversal->NATLease = 0;
+ traversal->retryInterval = 0;
+ uDNS_SendNATMsg(m, traversal);
}
- return mDNStrue;
+ // Even if we DIDN'T make a successful UPnP mapping yet, we might still have a partially-open TCP connection we need to clean up
+ #ifdef _LEGACY_NAT_TRAVERSAL_
+ {
+ mStatus err = LNT_UnmapPort(m, traversal);
+ if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
+ }
+ #endif // _LEGACY_NAT_TRAVERSAL_
+ return(mStatus_NoError);
}
-mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
+mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal)
{
- NATPortMapRequest *req = &info->request.PortReq;
-
- req->vers = NATMAP_VERS;
- req->opcode = info->op;
- req->unused.NotAnInteger = 0;
- req->priv = port;
- req->pub = port;
- req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
+ mStatus status;
+ mDNS_Lock(m);
+ status = mDNS_StartNATOperation_internal(m, traversal);
+ mDNS_Unlock(m);
+ return(status);
}
-mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
+mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal)
{
- if (!m->uDNS_info.Router.ip.v4.NotAnInteger)
- {
- debugf("No router. Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY);
- info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY;
- info->RetryInterval = NATMAP_INIT_RETRY;
- return;
- }
- SendNATMsg(info, m);
- return;
+ mStatus status;
+ mDNS_Lock(m);
+ status = mDNS_StopNATOperation_internal(m, traversal);
+ mDNS_Unlock(m);
+ return(status);
}
-mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Long-Lived Queries
+#endif
+
+mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
{
- NATOp_t op;
- NATTraversalInfo *info;
-
- if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP;
- else if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP;
- else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; }
-
- if (srs->uDNS_info.NATinfo) { LogMsg("Error: StartNATPortMap - NAT info already initialized!"); FreeNATInfo(m, srs->uDNS_info.NATinfo); }
- info = AllocNATInfo(m, op, ReceivePortMapReply);
- srs->uDNS_info.NATinfo = info;
- info->reg.ServiceRegistration = srs;
- info->state = NATState_Request;
-
- FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
- SendInitialPMapReq(m, info);
- return;
-
- error:
- startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+ LogOperation("StartLLQPolling: %##s", q->qname.c);
+ q->state = LLQ_Poll;
+ q->ThisQInterval = LLQ_POLL_INTERVAL;
+ q->LastQTime = m->timenow - q->ThisQInterval; // trigger immediate poll
+ SetNextQueryTime(m, q);
}
-mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
+// Forward reference
+mDNSlocal void LLQNatMapComplete(mDNS *m, NATTraversalInfo *n);
+
+mDNSlocal void StartLLQNatMap(mDNS *m, DNSQuestion *q)
{
- if (nat->state == NATState_Established) // let other edge-case states expire for simplicity
- {
- // zero lease
- nat->request.PortReq.lease.NotAnInteger = 0;
- nat->state = NATState_Request;
- SendNATMsg(nat, m);
- }
-#ifdef _LEGACY_NAT_TRAVERSAL_
- else if (nat->state == NATState_Legacy)
- {
- mStatus err = mStatus_NoError;
- mDNSBool tcp = srs ? DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse;
- err = LNT_UnmapPort(nat->PublicPort, tcp);
- if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
- }
-#else
- (void)srs; // unused
-#endif // _LEGACY_NAT_TRAVERSAL_
+ LogOperation("StartLLQNatMap: LLQ_NatMapWaitUDP");
+ mDNSPlatformMemZero(&q->NATInfoUDP, sizeof(NATTraversalInfo));
+ q->NATInfoUDP.IntPort = q->NATInfoUDP.RequestedPort = m->UnicastPort4;
+ q->NATInfoUDP.Protocol = NATOp_MapUDP;
+ q->NATInfoUDP.clientCallback = LLQNatMapComplete;
+ q->NATInfoUDP.clientContext = q; // Must be set non-null so we know this NATTraversalInfo object is in use
+ mDNS_StartNATOperation_internal(m, &q->NATInfoUDP);
}
-mDNSlocal void StartLLQNatMap(mDNS *m)
+mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data, mDNSBool includeQuestion)
{
- NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply);
- uDNS_GlobalInfo *u = &m->uDNS_info;
-
- u->LLQNatInfo = info;
+ AuthRecord rr;
+ ResourceRecord *opt = &rr.resrec;
+ rdataOPT *optRD;
- info->reg.RecordRegistration = mDNSNULL;
- info->reg.ServiceRegistration = mDNSNULL;
- info->state = NATState_Request;
- FormatPortMaprequest(info, m->UnicastPort4);
- SendInitialPMapReq(m, info);
- return;
- }
+ //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
+ if (includeQuestion)
+ {
+ ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
+ if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
+ }
+ // locate OptRR if it exists, set pointer to end
+ // !!!KRS implement me
-// if LLQ NAT context unreferenced, delete the mapping
-mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
- {
- NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo;
- DNSQuestion *q;
-
- if (!nat) return;
+ // format opt rr (fields not specified are zero-valued)
+ mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+ opt->rdlength = LLQ_OPT_RDLEN;
+ opt->rdestimate = LLQ_OPT_RDLEN;
- for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
- if (q->LongLived && q->uDNS_info.llq->NATMap) return;
+ optRD = &rr.resrec.rdata->u.opt;
+ optRD->opt = kDNSOpt_LLQ;
+ optRD->optlen = LLQ_OPTLEN;
+ optRD->OptData.llq = *data;
+ ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
+ if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
- //to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration
- if (nat->state == NATState_Established || nat->state == NATState_Legacy)
- DeleteNATPortMapping(m, nat, mDNSNULL); // for simplicity we allow other states to expire
- FreeNATInfo(m, nat); // note: this clears the global LLQNatInfo pointer
+ return ptr;
}
- // ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - host name and interface management
-#endif
+mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
+ {
+ InitializeDNSMessage(&msg->h, question->TargetQID, uQueryFlags);
-// if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
-// for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
-mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainname *dst)
+ *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
+ if (!*endPtr)
+ {
+ LogMsg("ERROR: Unicast query out of space in packet");
+ return mStatus_UnknownErr;
+ }
+ return mStatus_NoError;
+ }
+
+// Normally called with llq set.
+// May be called with llq NULL, when retransmitting a lost Challenge Response
+mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const LLQOptData *llq)
{
- uDNS_HostnameInfo *hi = u->Hostnames;
- (void)srv; // unused
+ mDNSu8 *responsePtr = m->omsg.data;
+ mStatus err;
+ LLQOptData llqBuf;
- dst->c[0] = 0;
- while (hi)
+ if (q->ntries++ == kLLQ_MAX_TRIES)
{
- if (hi->arv4 && (hi->arv4->uDNS_info.state == regState_Registered || hi->arv4->uDNS_info.state == regState_Refresh))
- {
- AssignDomainName(dst, hi->arv4->resrec.name);
- return mDNStrue;
- }
- if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh))
- {
- AssignDomainName(dst, hi->arv4->resrec.name);
- return mDNStrue;
- }
- hi = hi->next;
+ LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s Will re-try in %d minutes",
+ kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
+ q->state = LLQ_Retry;
+ q->LastQTime = m->timenow;
+ q->ThisQInterval = (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
+ SetNextQueryTime(m, q);
+ // !!!KRS give a callback error in these cases?
+ return;
}
- if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; }
- return mDNSfalse;
- }
+ if (!llq) // Retransmission: need to make a new LLQOptData
+ {
+ llqBuf.vers = kLLQ_Vers;
+ llqBuf.llqOp = kLLQOp_Setup;
+ llqBuf.err = LLQErr_NoError;
+ llqBuf.id = q->id;
+ llqBuf.llqlease = q->origLease;
+ llq = &llqBuf;
+ }
-mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- ExtraResourceRecord *e;
+ q->LastQTime = m->timenow;
+ q->ThisQInterval = q->tcp ? 0 : (kLLQ_INIT_RESEND * q->ntries * mDNSPlatformOneSecond); // If using TCP, don't need to retransmit
+ SetNextQueryTime(m, q);
- // Target change if:
- // We have a target and were previously waiting for one, or
- // We had a target and no longer do, or
- // The target has changed
+ if (constructQueryMsg(&m->omsg, &responsePtr, q)) goto error;
+ responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse);
+ if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
- domainname newtarget;
- domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
- mDNSBool HaveTarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget);
- mDNSBool TargetChanged = (HaveTarget && srs->uDNS_info.state == regState_NoTarget) || (curtarget->c[0] && !HaveTarget) || !SameDomainName(curtarget, &newtarget);
- mDNSBool HaveZoneData = srs->uDNS_info.ns.ip.v4.NotAnInteger ? mDNStrue : mDNSfalse;
-
- // Nat state change if:
- // We were behind a NAT, and now we are behind a new NAT, or
- // We're not behind a NAT but our port was previously mapped to a different public port
- // We were not behind a NAT and now we are
-
- NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
- mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
- mDNSBool NATChanged = mDNSfalse;
- mDNSBool NowBehindNAT = port.NotAnInteger && IsPrivateV4Addr(&u->AdvertisedV4);
- mDNSBool WereBehindNAT = nat != mDNSNULL;
- mDNSBool NATRouterChanged = nat && nat->Router.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger;
- mDNSBool PortWasMapped = nat && (nat->state == NATState_Established || nat->state == NATState_Legacy) && nat->PublicPort.NotAnInteger != port.NotAnInteger;
-
- if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue;
- else if (!NowBehindNAT && PortWasMapped) NATChanged = mDNStrue;
- else if (!WereBehindNAT && NowBehindNAT) NATChanged = mDNStrue;
-
- if (!TargetChanged && !NATChanged) return;
+ //LogOperation("sendChallengeResponse %#a:%d %d %p %d", &q->servAddr, mDNSVal16(q->servPort), q->tcp, q->AuthInfo, responsePtr - (mDNSu8 *)&m->omsg);
+ err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
+ if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err);
+ // on error, we procede as normal and retry after the appropriate interval
- debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d",
- srs->RR_SRV.resrec.name->c, HaveZoneData, TargetChanged, HaveTarget, NowBehindNAT, WereBehindNAT, NATRouterChanged, PortWasMapped);
-
- switch(srs->uDNS_info.state)
- {
- case regState_FetchingZoneData:
- case regState_Cancelled:
- case regState_DeregPending:
- case regState_DeregDeferred:
- case regState_Unregistered:
- case regState_NATMap:
- case regState_ExtraQueued:
- // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
- // or is in the process of, or has already been, deregistered
- return;
-
- case regState_Pending:
- case regState_Refresh:
- case regState_UpdatePending:
- // let the in-flight operation complete before updating
- srs->uDNS_info.SRVUpdateDeferred = mDNStrue;
- return;
-
- case regState_NATError:
- if (!NATChanged) return;
- // if nat changed, register if we have a target (below)
+ return;
- case regState_NoTarget:
- if (HaveTarget)
- {
- debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
- if (!HaveZoneData)
- {
- srs->uDNS_info.state = regState_FetchingZoneData;
- startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
- }
- else
- {
- if (nat && (NATChanged || !NowBehindNAT)) { srs->uDNS_info.NATinfo = mDNSNULL; FreeNATInfo(m, nat); }
- if (NATChanged && NowBehindNAT) { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
- else SendServiceRegistration(m, srs);
- }
- }
- return;
-
- case regState_Registered:
- // target or nat changed. deregister service. upon completion, we'll look for a new target
- debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c);
- for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered
- srs->uDNS_info.SRVChanged = mDNStrue;
- SendServiceDeregistration(m, srs);
- return;
- }
+ error:
+ q->state = LLQ_Error;
}
-mDNSlocal void UpdateSRVRecords(mDNS *m)
+mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const q, const rdataOPT *opt)
{
- ServiceRecordSet *srs;
+ mStatus err = mStatus_NoError;
- for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs);
- }
+ if (rcode && rcode != kDNSFlag1_RC_NXDomain)
+ { LogMsg("ERROR: recvSetupResponse %##s - rcode && rcode != kDNSFlag1_RC_NXDomain", q->qname.c); goto fail; }
-mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
- {
- uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext;
-
- if (result == mStatus_MemFree)
+ if (opt->OptData.llq.llqOp != kLLQOp_Setup)
+ { LogMsg("ERROR: recvSetupResponse %##s - bad op %d", q->qname.c, opt->OptData.llq.llqOp); goto fail; }
+
+ if (opt->OptData.llq.vers != kLLQ_Vers)
+ { LogMsg("ERROR: recvSetupResponse %##s - bad vers %d", q->qname.c, opt->OptData.llq.vers); goto fail; }
+
+ if (q->state == LLQ_InitialRequest)
{
- if (hi)
+ const LLQOptData *const llq = &opt->OptData.llq;
+ //LogOperation("Got LLQ_InitialRequest");
+
+ switch(llq->err)
{
- if (hi->arv4 == rr) hi->arv4 = mDNSNULL;
- else if (hi->arv4 == rr) hi->arv6 = mDNSNULL;
- rr->RecordContext = mDNSNULL;
- if (!hi->arv4 && !hi->arv6) ufree(hi); // free hi when both v4 and v6 AuthRecs deallocated
+ case LLQErr_NoError: break;
+ case LLQErr_ServFull:
+ LogMsg("recvSetupResponse - received ServFull from server for LLQ %##s Retry in %lu sec", q->qname.c, llq->llqlease);
+ q->LastQTime = m->timenow;
+ q->ThisQInterval = ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond);
+ q->state = LLQ_Retry;
+ SetNextQueryTime(m, q);
+ case LLQErr_Static:
+ q->state = LLQ_Static;
+ q->ThisQInterval = 0;
+ LogMsg("LLQ %##s: static", q->qname.c);
+ goto exit;
+ case LLQErr_FormErr:
+ LogMsg("ERROR: recvSetupResponse - received FormErr from server for LLQ %##s", q->qname.c);
+ goto error;
+ case LLQErr_BadVers:
+ LogMsg("ERROR: recvSetupResponse - received BadVers from server");
+ goto error;
+ case LLQErr_UnknownErr:
+ LogMsg("ERROR: recvSetupResponse - received UnknownErr from server for LLQ %##s", q->qname.c);
+ goto error;
+ default:
+ LogMsg("ERROR: recvSetupResponse - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
+ goto error;
}
- ufree(rr);
- return;
- }
- if (result)
+ if (q->origLease != llq->llqlease)
+ debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->origLease, llq->llqlease);
+
+ // cache expiration in case we go to sleep before finishing setup
+ q->origLease = llq->llqlease;
+ q->expire = m->timenow + ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond);
+
+ // update state
+ q->state = LLQ_SecondaryRequest;
+ q->id = llq->id;
+ // if (q->ntries == 1) goto exit; // Test for simulating loss of challenge response packet
+ q->ntries = 0; // first attempt to send response
+
+ sendChallengeResponse(m, q, llq);
+ goto exit;
+
+ error:
+ q->state = LLQ_Error;
+ goto exit;
+ }
+
+ if (q->state == LLQ_SecondaryRequest)
{
- // don't unlink or free - we can retry when we get a new address/router
- if (rr->resrec.rrtype == kDNSType_A)
- LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
- else
- LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
- if (!hi) { ufree(rr); return; }
- if (rr->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
+ //LogOperation("Got LLQ_SecondaryRequest");
- if ((!hi->arv4 || hi->arv4->uDNS_info.state == regState_Unregistered) &&
- (!hi->arv6 || hi->arv6->uDNS_info.state == regState_Unregistered))
+ // Fix this immediately if not sooner. Copy the id from the LLQOptData into our DNSQuestion struct. This is only
+ // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger
+ // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
+ // if the server sends back SERVFULL or STATIC.
+ if (q->AuthInfo)
{
- // only deliver status if both v4 and v6 fail
- rr->RecordContext = (void *)hi->StatusContext;
- if (hi->StatusCallback)
- hi->StatusCallback(m, rr, result); // client may NOT make API calls here
- rr->RecordContext = (void *)hi;
+ LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", opt->OptData.llq.id.l[0], opt->OptData.llq.id.l[1]);
+ q->id = opt->OptData.llq.id;
}
- return;
+
+ if (opt->OptData.llq.err) { LogMsg("ERROR: recvSetupResponse %##s code %d from server", q->qname.c, opt->OptData.llq.err); q->state = LLQ_Error; goto fail; }
+ if (!mDNSSameOpaque64(&q->id, &opt->OptData.llq.id))
+ { LogMsg("recvSetupResponse - ID changed. discarding"); goto exit; } // this can happen rarely (on packet loss + reordering)
+ q->expire = m->timenow + ((mDNSs32)opt->OptData.llq.llqlease * mDNSPlatformOneSecond );
+ q->LastQTime = m->timenow;
+ q->ThisQInterval = ((mDNSs32)opt->OptData.llq.llqlease * (mDNSPlatformOneSecond / 2));
+ q->origLease = opt->OptData.llq.llqlease;
+ q->state = LLQ_Established;
+ SetNextQueryTime(m, q);
+ goto exit;
}
- // register any pending services that require a target
- UpdateSRVRecords(m);
-
- // Deliver success to client
- if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
- if (rr->resrec.rrtype == kDNSType_A)
- LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
- else
- LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
- rr->RecordContext = (void *)hi->StatusContext;
- if (hi->StatusCallback)
- hi->StatusCallback(m, rr, result); // client may NOT make API calls here
- rr->RecordContext = (void *)hi;
- }
+ if (q->state == LLQ_Established) goto exit;
-// register record or begin NAT traversal
-mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
-
- if (u->AdvertisedV4.ip.v4.NotAnInteger && h->arv4->uDNS_info.state == regState_Unregistered)
- {
- if (IsPrivateV4Addr(&u->AdvertisedV4))
- StartGetPublicAddr(m, h->arv4);
- else
- {
- LogMsg("Advertising %##s IP %.4a", h->arv4->resrec.name->c, &u->AdvertisedV4.ip.v4);
- uDNS_RegisterRecord(m, h->arv4);
- }
- }
- if (u->AdvertisedV6.ip.v6.b[0] && h->arv6->uDNS_info.state == regState_Unregistered)
+ LogMsg("ERROR: recvSetupResponse %##s - bad state %d", q->qname.c, q->state);
+
+fail:
+ err = mStatus_UnknownErr;
+
+exit:
+
+ if (err)
{
- LogMsg("Advertising %##s IP %.16a", h->arv4->resrec.name->c, &u->AdvertisedV6.ip.v6);
- uDNS_RegisterRecord(m, h->arv6);
+ LogOperation("recvSetupResponse error %d ", err);
+ StartLLQPolling(m, q);
}
}
-mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+// Returns mDNStrue if mDNSCoreReceiveResponse should treat this packet as a series of add/remove instructions (like an mDNS response)
+// Returns mDNSfalse if mDNSCoreReceiveResponse should treat this as a single authoritative result (like a normal unicast DNS response)
+mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
{
- const domainname *pktname = &answer->rdata->u.name;
- domainname *storedname = &m->uDNS_info.StaticHostname;
- uDNS_HostnameInfo *h = m->uDNS_info.Hostnames;
-
- (void)question;
-
- debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
- if (AddRecord && !SameDomainName(pktname, storedname))
+ DNSQuestion pktQ, *q;
+ if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ))
{
- AssignDomainName(storedname, pktname);
- while (h)
+ const rdataOPT *opt = GetLLQOptData(m, msg, end);
+ if (opt)
{
- if ((h->arv4 && (h->arv4->uDNS_info.state == regState_FetchingZoneData || h->arv4->uDNS_info.state == regState_Pending || h->arv4->uDNS_info.state == regState_NATMap)) ||
- (h->arv6 && (h->arv6->uDNS_info.state == regState_FetchingZoneData || h->arv6->uDNS_info.state == regState_Pending)))
+ for (q = m->Questions; q; q = q->next)
{
- // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds
- m->uDNS_info.DelaySRVUpdate = mDNStrue;
- m->uDNS_info.NextSRVUpdate = mDNSPlatformTimeNow(m) + (5 * mDNSPlatformOneSecond);
- return;
+ if (q->LongLived && q->qtype == pktQ.qtype && q->qnamehash == pktQ.qnamehash && SameDomainName(&q->qname, &pktQ.qname))
+ {
+ debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d",
+ q->qname.c, DNSTypeName(q->qtype), q->state, srcaddr, &q->servAddr,
+ opt->OptData.llq.id.l[0], opt->OptData.llq.id.l[1], q->id.l[0], q->id.l[1], opt->OptData.llq.llqOp);
+ if (q->state == LLQ_Poll)
+ {
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ return uDNS_LLQ_Poll;
+ }
+ else if (q->state == LLQ_Established || (q->state == LLQ_Refresh && msg->h.numAnswers))
+ {
+ if (opt->OptData.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id))
+ {
+ mDNSu8 *ackEnd;
+ if (q->LongLived && q->state == LLQ_Poll && !mDNSIPPortIsZero(q->servPort)) q->ThisQInterval = LLQ_POLL_INTERVAL;
+ else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+ //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ InitializeDNSMessage(&m->omsg.h, msg->h.id, ResponseFlags);
+ ackEnd = putLLQ(&m->omsg, m->omsg.data, mDNSNULL, &opt->OptData.llq, mDNSfalse);
+ if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, srcaddr, srcport, mDNSNULL, mDNSNULL);
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ return uDNS_LLQ_Events;
+ }
+ }
+ if (mDNSSameOpaque16(msg->h.id, q->TargetQID))
+ {
+ if (opt->OptData.llq.llqOp == kLLQOp_Refresh && q->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id))
+ {
+ if (opt->OptData.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->OptData.llq.err);
+ else
+ {
+ //LogOperation("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
+ GrantCacheExtensions(m, q, opt->OptData.llq.llqlease);
+ q->expire = q->LastQTime + ((mDNSs32)opt->OptData.llq.llqlease * mDNSPlatformOneSecond );
+ q->ThisQInterval = ((mDNSs32)opt->OptData.llq.llqlease * (mDNSPlatformOneSecond/2));
+ q->origLease = opt->OptData.llq.llqlease;
+ q->state = LLQ_Established;
+ }
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ return uDNS_LLQ_Events;
+ }
+ if (q->state < LLQ_Static)
+ {
+ if (mDNSSameAddress(srcaddr, &q->servAddr))
+ {
+ LLQ_State oldstate = q->state;
+ recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, opt);
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ //DumpPacket(m, msg, end);
+ // If this is our Ack+Answers packet resulting from a correct challenge response, then it's a full list
+ // of answers, and any cache answers we have that are not included in this packet need to be flushed
+ //LogMsg("uDNS_recvLLQResponse: recvSetupResponse state %d returning %d", oldstate, oldstate != LLQ_SecondaryRequest);
+ return (oldstate == LLQ_SecondaryRequest ? uDNS_LLQ_Setup : uDNS_LLQ_Events);
+ }
+ }
+ }
+ }
}
- h = h->next;
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ //LogMsg("uDNS_recvLLQResponse: returning 0");
}
- UpdateSRVRecords(m);
- }
- else if (!AddRecord && SameDomainName(pktname, storedname))
- {
- storedname->c[0] = 0;
- UpdateSRVRecords(m);
}
+ return uDNS_LLQ_Not;
}
-mDNSlocal void GetStaticHostname(mDNS *m)
- {
- char buf[MAX_ESCAPED_DOMAIN_NAME];
- DNSQuestion *q = &m->uDNS_info.ReverseMap;
- mDNSu8 *ip = m->uDNS_info.AdvertisedV4.ip.v4.b;
- mStatus err;
-
- if (m->uDNS_info.ReverseMapActive)
- {
- uDNS_StopQuery(m, q);
- m->uDNS_info.ReverseMapActive = mDNSfalse;
- }
-
- m->uDNS_info.StaticHostname.c[0] = 0;
- if (!m->uDNS_info.AdvertisedV4.ip.v4.NotAnInteger) return;
- ubzero(q, sizeof(*q));
- mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
- if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
+// Forward declaration
+mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease);
- q->InterfaceID = mDNSInterface_Any;
- q->Target = zeroAddr;
- q->qtype = kDNSType_PTR;
- q->qclass = kDNSClass_IN;
- q->LongLived = mDNSfalse;
- q->ExpectUnique = mDNSfalse;
- q->ForceMCast = mDNSfalse;
- q->QuestionCallback = FoundStaticHostname;
- q->QuestionContext = mDNSNULL;
-
- err = uDNS_StartQuery(m, q);
- if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
- else m->uDNS_info.ReverseMapActive = mDNStrue;
- }
+// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
+struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
-mDNSlocal void AssignHostnameInfoAuthRecord(mDNS *m, uDNS_HostnameInfo *hi, int type)
+// tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
+// Private DNS operations -- private queries, private LLQs, private record updates and private service updates
+mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
{
- AuthRecord **dst = (type == mDNSAddrType_IPv4 ? &hi->arv4 : &hi->arv6);
- AuthRecord *ar = umalloc(sizeof(*ar));
- uDNS_GlobalInfo *u = &m->uDNS_info;
-
- if (type != mDNSAddrType_IPv4 && type != mDNSAddrType_IPv6) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - bad type %d", type); return; }
- if (!ar) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - malloc"); return; }
-
- mDNS_SetupResourceRecord(ar, mDNSNULL, 0, type == mDNSAddrType_IPv4 ? kDNSType_A : kDNSType_AAAA, 1, kDNSRecordTypeKnownUnique, HostnameCallback, hi);
- AssignDomainName(ar->resrec.name, &hi->fqdn);
+ tcpInfo_t *tcpInfo = (tcpInfo_t *)context;
+ mDNSBool closed = mDNSfalse;
+ mDNSu8 *end;
+ mDNS *m = tcpInfo->m;
+ DomainAuthInfo *AuthInfo =
+ tcpInfo->question ? tcpInfo->question->AuthInfo :
+ tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
+ tcpInfo->rr ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL;
+
+ tcpInfo_t **backpointer =
+ tcpInfo->question ? &tcpInfo->question->tcp :
+ tcpInfo->srs ? &tcpInfo->srs->tcp :
+ tcpInfo->rr ? &tcpInfo->rr->tcp : mDNSNULL;
+ if (!backpointer) LogMsg("tcpCallback: Purpose of connection unidentified");
+ else if (*backpointer != tcpInfo)
+ LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
+ mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, tcpInfo->question, tcpInfo->srs, tcpInfo->rr);
+
+ if (err) goto exit;
- // only set RData if we have a valid IP
- if (type == mDNSAddrType_IPv4 && u->AdvertisedV4.ip.v4.NotAnInteger)
- {
- if (u->MappedV4.ip.v4.NotAnInteger) ar->resrec.rdata->u.ipv4 = u->MappedV4.ip.v4;
- else ar->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4;
- }
- else if (type == mDNSAddrType_IPv6 && u->AdvertisedV6.ip.v6.b[0])
- {
- ar->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
- }
-
- ar->uDNS_info.state = regState_Unregistered;
-
- if (*dst)
+ if (ConnectionEstablished)
{
- LogMsg("ERROR: AssignHostnameInfoAuthRecord - overwriting %s AuthRec", type == mDNSAddrType_IPv4 ? "IPv4" : "IPv6");
- unlinkAR(&u->RecordRegistrations, *dst);
- (*dst)->RecordContext = mDNSNULL; // defensively clear backpointer to avoid doubly-referenced context
- }
-
- *dst = ar;
- }
+ // connection is established - send the message
+ if (tcpInfo->question && tcpInfo->question->LongLived && (tcpInfo->question->state == LLQ_Established || tcpInfo->question->state == LLQ_Refresh))
+ {
+ //LogMsg("tcpCallback calling sendLLQRefresh %##s (%s)", tcpInfo->question->qname.c, DNSTypeName(tcpInfo->question->qtype));
+ mDNS_Lock(m);
+ sendLLQRefresh(m, tcpInfo->question, tcpInfo->question->origLease);
+ mDNS_Unlock(m);
+ return;
+ }
+ else if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state != LLQ_Poll)
+ {
+ LLQOptData llqData; // set llq rdata
+ llqData.vers = kLLQ_Vers;
+ llqData.llqOp = kLLQOp_Setup;
+ llqData.err = LLQErr_NoError;
+ llqData.err = mDNSVal16(tcpInfo->question->eventPort); // Tell server our external NAT-mapped UDP port
+ if (llqData.err == 0) llqData.err = 5353; // If not using NAT, then we need events sent directly to 5353
+ LogOperation("tcpCallback: eventPort %d", llqData.err);
+ llqData.id = zeroOpaque64;
+ llqData.llqlease = kLLQ_DefLease;
+ InitializeDNSMessage(&tcpInfo->request.h, tcpInfo->question->TargetQID, uQueryFlags);
+ //LogMsg("tcpCallback: putLLQ %p", AuthInfo);
+ end = putLLQ(&tcpInfo->request, tcpInfo->request.data, tcpInfo->question, &llqData, mDNStrue);
+
+ if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; }
+ }
+ else if (tcpInfo->question)
+ {
+ err = constructQueryMsg(&tcpInfo->request, &end, tcpInfo->question);
+ if (err) { LogMsg("ERROR: tcpCallback: constructQueryMsg - %ld", err); err = mStatus_UnknownErr; goto exit; }
+ }
+ else
+ end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen;
+ err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo);
-// Deregister hostnames and register new names for each host domain with the current global
-// values for the hostlabel and primary IP address
-mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- uDNS_HostnameInfo *i;
+ if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; }
- for (i = u->Hostnames; i; i = i->next)
- {
- if (i->arv4 && i->arv4->uDNS_info.state != regState_Unregistered &&
- i->arv4->resrec.rdata->u.ipv4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger &&
- i->arv4->resrec.rdata->u.ipv4.NotAnInteger !=u->MappedV4.ip.v4.NotAnInteger)
+ // Record time we sent this question
+ if (tcpInfo->question)
{
- uDNS_DeregisterRecord(m, i->arv4);
- i->arv4 = mDNSNULL;
+ mDNS_Lock(m);
+ tcpInfo->question->LastQTime = m->timenow;
+ tcpInfo->question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+ SetNextQueryTime(m, tcpInfo->question);
+ mDNS_Unlock(m);
}
- if (i->arv6 && !mDNSPlatformMemSame(i->arv6->resrec.rdata->u.ipv6.b, u->AdvertisedV6.ip.v6.b, 16) && i->arv6->uDNS_info.state != regState_Unregistered)
+ }
+ else
+ {
+ long n;
+ if (tcpInfo->nread < 2) // First read the two-byte length preceeding the DNS message
{
- uDNS_DeregisterRecord(m, i->arv6);
- i->arv6 = mDNSNULL;
- }
-
- if (!i->arv4 && u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv4);
- else if (i->arv4 && i->arv4->uDNS_info.state == regState_Unregistered) i->arv4->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4; // simply overwrite unregistered
- if (!i->arv6 && u->AdvertisedV6.ip.v6.b[0]) AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv6);
- else if (i->arv6 &&i->arv6->uDNS_info.state == regState_Unregistered) i->arv6->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6;
+ mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen;
+ n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
+ if (n < 0) { LogMsg("ERROR:tcpCallback - attempt to read message length failed (%d)", n); err = mStatus_ConnFailed; goto exit; }
+ else if (closed)
+ {
+ // It's perfectly fine for this socket to close after the first reply. The server might
+ // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open.
+ // We'll only log this event if we've never received a reply before.
+ // BIND 9 appears to close an idle connection after 30 seconds.
+ if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread);
+ err = mStatus_ConnFailed;
+ goto exit;
+ }
- AdvertiseHostname(m, i);
- }
- }
+ tcpInfo->nread += n;
+ if (tcpInfo->nread < 2) goto exit;
-mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- uDNS_HostnameInfo *ptr, *new;
+ tcpInfo->replylen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]);
+ if (tcpInfo->replylen < sizeof(DNSMessageHeader))
+ { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; }
- mDNS_Lock(m);
+ tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
+ if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
+ }
- // check if domain already registered
- for (ptr = u->Hostnames; ptr; ptr = ptr->next)
- {
- if (SameDomainName(fqdn, &ptr->fqdn))
- { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
- }
+ n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed);
- // allocate and format new address record
- new = umalloc(sizeof(*new));
- if (!new) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; }
- ubzero(new, sizeof(*new));
- new->next = u->Hostnames;
- u->Hostnames = new;
-
- AssignDomainName(&new->fqdn, fqdn);
- new->StatusCallback = StatusCallback;
- new->StatusContext = StatusContext;
+ if (n < 0) { LogMsg("ERROR: tcpCallback - read returned %d", n); err = mStatus_ConnFailed; goto exit; }
+ else if (closed) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread); err = mStatus_ConnFailed; goto exit; }
- if (u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv4);
- else new->arv4 = mDNSNULL;
- if (u->AdvertisedV6.ip.v6.b[0]) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv6);
- else new->arv6 = mDNSNULL;
+ tcpInfo->nread += n;
+
+ if ((tcpInfo->nread - 2) == tcpInfo->replylen)
+ {
+ AuthRecord *rr = tcpInfo->rr;
+ DNSMessage *reply = tcpInfo->reply;
+ mDNSu8 *end = (mDNSu8 *)tcpInfo->reply + tcpInfo->replylen;
+ mDNSAddr Addr = tcpInfo->Addr;
+ mDNSIPPort Port = tcpInfo->Port;
+ tcpInfo->numReplies++;
+ tcpInfo->reply = mDNSNULL; // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
+ tcpInfo->nread = 0;
+ tcpInfo->replylen = 0;
+
+ // If we're going to dispose this connection, do it FIRST, before calling client callback
+ if (!tcpInfo->question || !tcpInfo->question->LongLived) { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
+
+ if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+ {
+ mDNS_Lock(m);
+ LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
+ CompleteDeregistration(m, rr); // Don't touch rr after this
+ mDNS_Unlock(m);
+ }
+ else
+ mDNSCoreReceive(m, reply, end, &Addr, Port, (sock->flags & kTCPSocketFlags_UseTLS) ? (mDNSAddr *)1 : mDNSNULL, zeroIPPort, 0);
+ // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
+
+ mDNSPlatformMemFree(reply);
+ return;
+ }
+ }
- if (u->AdvertisedV6.ip.v6.b[0] || u->AdvertisedV4.ip.v4.NotAnInteger) AdvertiseHostname(m, new);
-
exit:
- mDNS_Unlock(m);
- }
-mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- uDNS_HostnameInfo **ptr = &u->Hostnames;
+ if (err)
+ {
+ // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation
+ // we won't end up double-disposing our tcpInfo_t
+ *backpointer = mDNSNULL;
- mDNS_Lock(m);
+ if (tcpInfo->question)
+ {
+ DNSQuestion *q = tcpInfo->question;
+ mDNS_Lock(m); // Need to grab the lock to get m->timenow
+ if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL)
+ {
+ q->LastQTime = m->timenow;
+ q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
+ SetNextQueryTime(m, q);
+ }
+ mDNS_Unlock(m);
+ // ConnFailed is actually okay. It just means that the server closed the connection but the LLQ is still okay.
+ // If the error isn't ConnFailed, then the LLQ is in bad shape.
+ if (err != mStatus_ConnFailed) tcpInfo->question->state = LLQ_Error;
+ }
- while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
- if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
- else
- {
- uDNS_HostnameInfo *hi = *ptr;
- *ptr = (*ptr)->next; // unlink
- if (hi->arv4)
+ if (tcpInfo->rr)
{
- hi->arv4->RecordContext = mDNSNULL; // about to free wrapper struct
- if (hi->arv4->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv4);
- else { ufree(hi->arv4); hi->arv4 = mDNSNULL; }
+ mDNSBool deregPending = (tcpInfo->rr->state == regState_DeregPending) ? mDNStrue : mDNSfalse;
+
+ UnlinkAuthRecord(m, tcpInfo->rr);
+ tcpInfo->rr->state = regState_Unregistered;
+
+ if (!deregPending)
+ {
+ // Right now tcpCallback does not run holding the lock, so no need to drop the lock
+ //mDNS_DropLockBeforeCallback();
+ if (tcpInfo->rr->RecordCallback)
+ tcpInfo->rr->RecordCallback(m, tcpInfo->rr, err);
+ //mDNS_ReclaimLockAfterCallback();
+ // NOTE: not safe to touch any client structures here --
+ // once we issue the callback, client is free to reuse or deallocate the srs memory
+ }
}
- if (hi->arv6)
+
+ if (tcpInfo->srs)
{
- hi->arv6->RecordContext = mDNSNULL; // about to free wrapper struct
- if (hi->arv6->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv6);
- else { ufree(hi->arv6); hi->arv6 = mDNSNULL; }
+ mDNSBool deregPending = (tcpInfo->srs->state == regState_DeregPending) ? mDNStrue : mDNSfalse;
+
+ unlinkSRS(m, tcpInfo->srs);
+ tcpInfo->srs->state = regState_Unregistered;
+
+ if (!deregPending)
+ {
+ // Right now tcpCallback does not run holding the lock, so no need to drop the lock
+ //mDNS_DropLockBeforeCallback();
+ tcpInfo->srs->ServiceCallback(m, tcpInfo->srs, err);
+ //mDNS_ReclaimLockAfterCallback();
+ // NOTE: not safe to touch any client structures here --
+ // once we issue the callback, client is free to reuse or deallocate the srs memory
+ }
}
- ufree(hi);
+
+ DisposeTCPConn(tcpInfo);
}
- UpdateSRVRecords(m);
- mDNS_Unlock(m);
}
-mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
+mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
+ TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port,
+ DNSQuestion *const question, ServiceRecordSet *const srs, AuthRecord *const rr)
{
- uDNS_GlobalInfo *u = &m->uDNS_info;
- mDNSBool v4Changed, v6Changed, RouterChanged;
-
- if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo V4 address - incorrect type. Discarding."); return; }
- if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo V6 address - incorrect type. Discarding."); return; }
- if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 router. Discarding."); return; }
+ mStatus err;
+ mDNSIPPort srcport = zeroIPPort;
+ tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
+ if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
+
+ mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
+ info->m = m;
+ if (msg)
+ {
+ info->request = *msg;
+ info->requestLen = (int) (end - ((mDNSu8*)msg));
+ }
+ info->question = question;
+ info->srs = srs;
+ info->rr = rr;
+ info->Addr = *Addr;
+ info->Port = Port;
+
+ info->sock = mDNSPlatformTCPSocket(m, flags, &srcport);
+ if (!info->sock) { LogMsg("SendServiceRegistration: uanble to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+ err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info);
+
+ if (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); }
+ else if (err != mStatus_ConnPending ) { LogMsg("MakeTCPConnection: connection failed"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+ return(info);
+ }
- mDNS_Lock(m);
+mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
+ {
+ mDNSPlatformTCPCloseConnection(tcp->sock);
+ if (tcp->reply) mDNSPlatformMemFree(tcp->reply);
+ mDNSPlatformMemFree(tcp);
+ }
- v4Changed = (v4addr ? v4addr->ip.v4.NotAnInteger : 0) != u->AdvertisedV4.ip.v4.NotAnInteger;
- v6Changed = v6addr ? !mDNSPlatformMemSame(v6addr, &u->AdvertisedV6, sizeof(*v6addr)) : (u->AdvertisedV6.ip.v6.b[0] != 0);
- RouterChanged = (router ? router->ip.v4.NotAnInteger : 0) != u->Router.ip.v4.NotAnInteger;
-
-#if MDNS_DEBUGMSGS
- if (v4addr && (v4Changed || RouterChanged))
- LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d",
- u->AdvertisedV4.ip.v4.b[0], u->AdvertisedV4.ip.v4.b[1], u->AdvertisedV4.ip.v4.b[2], u->AdvertisedV4.ip.v4.b[3],
- v4addr->ip.v4.b[0], v4addr->ip.v4.b[1], v4addr->ip.v4.b[2], v4addr->ip.v4.b[3]);
-#endif // MDNS_DEBUGMSGS
-
- if ((v4Changed || RouterChanged) && u->MappedV4.ip.v4.NotAnInteger) u->MappedV4.ip.v4.NotAnInteger = 0;
- if (v4addr) u->AdvertisedV4 = *v4addr; else u->AdvertisedV4.ip.v4.NotAnInteger = 0;
- if (v6addr) u->AdvertisedV6 = *v6addr; else ubzero(u->AdvertisedV6.ip.v6.b, 16);
- if (router) u->Router = *router; else u->Router.ip.v4.NotAnInteger = 0;
- // setting router to zero indicates that nat mappings must be reestablished when router is reset
-
- if ((v4Changed || RouterChanged || v6Changed) && (v4addr && router))
+mDNSlocal void RemoveLLQNatMappings(mDNS *m, DNSQuestion *q)
+ {
+ if (q->NATInfoUDP.clientContext)
{
- // don't update these unless we've got V4
- UpdateHostnameRegistrations(m);
- UpdateSRVRecords(m);
- GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address
+ mDNS_StopNATOperation_internal(m, &q->NATInfoUDP);
+ q->NATInfoUDP.clientContext = mDNSNULL;
}
-
- mDNS_Unlock(m);
}
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Incoming Message Processing
-#endif
-
-mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr)
+mDNSlocal void startLLQHandshake(mDNS *m, DNSQuestion *q)
{
- CacheRecord *ptr;
-
- for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
- if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue;
+ mStatus err = mStatus_NoError;
+ if (q->AuthInfo)
+ {
+ LogOperation("startLLQHandshakePrivate Addr %#a%s Server %#a:%d%s %##s (%s) eventport %d",
+ &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
+ &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr) ? " (RFC 1918)" : "",
+ q->qname.c, DNSTypeName(q->qtype), mDNSVal16(q->eventPort));
- return mDNSfalse;
- }
+ if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&q->servAddr))
+ if (q->state == LLQ_InitialRequest)
+ {
+ // start
+ if (!q->NATInfoUDP.clientContext) { q->state = LLQ_NatMapWaitUDP; StartLLQNatMap(m, q); goto exit; }
+ else
+ {
+ LogMsg("startLLQHandshake state == LLQ_InitialRequest but already have NATInfoUDP.clientContext %##s (%s)",
+ q->qname.c, DNSTypeName(q->qtype));
+ err = mStatus_UnknownErr;
+ goto exit;
+ }
+ }
+ LogOperation("startLLQHandshake TCP %p %##s (%s)", q->tcp, q->qname.c, DNSTypeName(q->qtype));
+ if (q->tcp) LogMsg("startLLQHandshake: Already have TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ else q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
-mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
- {
- CacheRecord *ptr, *prev = mDNSNULL;
+ // update question state
+ //q->state = LLQ_InitialRequest;
+ q->state = LLQ_SecondaryRequest; // Right now, for private DNS, we skip the four-way LLQ handshake
+ q->origLease = kLLQ_DefLease;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
- for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next)
+ err = mStatus_NoError;
+ }
+ else
{
- if (SameResourceRecord(&ptr->resrec, &rr->resrec))
+ mDNSu8 *end;
+ LLQOptData llqData;
+
+ LogOperation("startLLQHandshake Addr %#a%s Server %#a:%d%s %##s (%s) RequestedPort %d",
+ &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
+ &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr) ? " (RFC 1918)" : "",
+ q->qname.c, DNSTypeName(q->qtype), mDNSVal16(q->NATInfoUDP.RequestedPort));
+
+ if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&q->servAddr))
{
- if (prev) prev->next = ptr->next;
- else question->uDNS_info.knownAnswers = ptr->next;
- ufree(ptr);
- return;
+ // start
+ if (!q->NATInfoUDP.clientContext) { q->state = LLQ_NatMapWaitUDP; StartLLQNatMap(m, q); }
+ else { err = mStatus_UnknownErr; goto exit; }
}
- prev = ptr;
- }
- LogMsg("removeKnownAnswer() called for record not in KA list");
- }
+ if (q->ntries++ >= kLLQ_MAX_TRIES)
+ { LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c); err = mStatus_UnknownErr; goto exit; }
-mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
- {
- CacheRecord *newCR = mDNSNULL;
- mDNSu32 size;
-
- size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
- newCR = (CacheRecord *)umalloc(size);
- if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; }
- umemcpy(newCR, rr, size);
- newCR->resrec.rdata = (RData*)&newCR->rdatastorage;
- newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength;
- newCR->resrec.name = &question->qname;
- newCR->next = question->uDNS_info.knownAnswers;
- question->uDNS_info.knownAnswers = newCR;
+ // set llq rdata
+ llqData.vers = kLLQ_Vers;
+ llqData.llqOp = kLLQOp_Setup;
+ llqData.err = LLQErr_NoError;
+ llqData.id = zeroOpaque64;
+ llqData.llqlease = kLLQ_DefLease;
+
+ InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+ end = putLLQ(&m->omsg, m->omsg.data, q, &llqData, mDNStrue);
+ if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); q->state = LLQ_Error; return; }
+
+ err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
+ // on error, we procede as normal and retry after the appropriate interval
+ if (err) { debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err); err = mStatus_NoError; }
+
+ // update question state
+ q->state = LLQ_InitialRequest;
+ q->origLease = kLLQ_DefLease;
+ q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
+ q->LastQTime = m->timenow - q->ThisQInterval;
+ SetNextQueryTime(m, q);
+
+ err = mStatus_NoError;
+ }
+
+exit:
+ if (err)
+ {
+ LogOperation("startLLQHandshake error %d ", err);
+ StartLLQPolling(m, q);
+ }
}
-mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question)
+// Called in normal client context (lock not held)
+mDNSlocal void LLQNatMapComplete(mDNS *m, NATTraversalInfo *n)
{
- const mDNSu8 *ptr;
- int i;
- CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL;
- LargeCacheRecord *lcr;
-
- if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; }
+ if (m->CurrentQuestion)
+ LogMsg("LLQNatMapComplete: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ m->CurrentQuestion = m->Questions;
- ptr = LocateAnswers(msg, end);
- if (!ptr) goto pkt_error;
-
- if (!msg->h.numAnswers)
+ while (m->CurrentQuestion)
{
- // delete the whole KA list
- ka = question->uDNS_info.knownAnswers;
- while (ka)
+ DNSQuestion *q = m->CurrentQuestion;
+ m->CurrentQuestion = m->CurrentQuestion->next;
+ if (q->LongLived)
{
- debugf("deriving goodbye for %##s", ka->resrec.name->c);
-
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- if (question != m->uDNS_info.CurrentQuery)
+ if (q->state == LLQ_NatMapWaitUDP)
{
- debugf("deriveGoodbyes - question removed via callback. returning.");
- return;
+ if (!n->Result)
+ {
+ q->state = LLQ_GetZoneInfo;
+ q->eventPort = n->ExternalPort;
+ startLLQHandshake(m, q);
+ }
+ else
+ {
+ LogMsg("LLQNatMapComplete error %d Internal %d Requested %d External %d", n->Result,
+ mDNSVal16(q->NATInfoUDP.IntPort), mDNSVal16(q->NATInfoUDP.RequestedPort), mDNSVal16(q->NATInfoUDP.ExternalPort));
+ RemoveLLQNatMappings(m, q);
+ StartLLQPolling(m, q);
+ }
}
- fptr = ka;
- ka = ka->next;
- ufree(fptr);
- }
- question->uDNS_info.knownAnswers = mDNSNULL;
- return;
- }
-
- // make a list of all the new answers
- for (i = 0; i < msg->h.numAnswers; i++)
- {
- lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord));
- if (!lcr) goto malloc_error;
- ubzero(lcr, sizeof(LargeCacheRecord));
- ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr);
- if (!ptr) goto pkt_error;
- cr = &lcr->r;
- if (ResourceRecordAnswersQuestion(&cr->resrec, question))
- {
- cr->next = answers;
- answers = cr;
}
- else ufree(cr);
}
-
- // make sure every known answer is in the answer list
- ka = question->uDNS_info.knownAnswers;
- while (ka)
+ m->CurrentQuestion = mDNSNULL;
+ }
+
+// if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname
+// for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query
+mDNSexport const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs)
+ {
+ LogOperation("GetServiceTarget %##s", srs->RR_SRV.resrec.name->c);
+
+ if (!srs->RR_SRV.AutoTarget) // If not automatically tracking this host's current name, just return the existing target
+ return(&srs->RR_SRV.resrec.rdata->u.srv.target);
+ else
{
- for (cr = answers; cr; cr = cr->next)
- { if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; }
- if (!cr)
+ HostnameInfo *hi = m->Hostnames;
+
+#if APPLE_OSX_mDNSResponder
+ DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
+ if (AuthInfo && AuthInfo->AutoTunnel)
{
- // record is in KA list but not answer list - remove from KA list
- if (prev) prev->next = ka->next;
- else question->uDNS_info.knownAnswers = ka->next;
- debugf("deriving goodbye for %##s", ka->resrec.name->c);
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- if (question != m->uDNS_info.CurrentQuery)
+ if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0)
{
- debugf("deriveGoodbyes - question removed via callback. returning.");
- return;
+ if (m->AutoTunnelHostAddr.b[0]) SetupLocalAutoTunnelInterface_internal(m);
+ return(mDNSNULL);
}
- fptr = ka;
- ka = ka->next;
- ufree(fptr);
+ return(&AuthInfo->AutoTunnelHostRecord.namestorage);
}
- else
+#endif APPLE_OSX_mDNSResponder
+
+ while (hi)
{
- prev = ka;
- ka = ka->next;
+ if (hi->arv4.state == regState_Registered || hi->arv4.state == regState_Refresh) return(hi->arv4.resrec.name);
+ if (hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh) return(hi->arv6.resrec.name);
+ hi = hi->next;
}
+ if (m->StaticHostname.c[0]) return(&m->StaticHostname);
+ return(mDNSNULL);
+ }
+ }
+
+// Called with lock held
+mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
+ {
+ mDNSu8 *ptr = m->omsg.data;
+ mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+ mDNSOpaque16 id;
+ mStatus err = mStatus_NoError;
+ const domainname *target;
+ mDNSu32 i;
+
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+ if (mDNSIPv4AddressIsZero(srs->ns.ip.v4)) { LogMsg("SendServiceRegistration - NS not set!"); return; }
+
+ id = mDNS_NewMessageID(m);
+ InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
+
+ // setup resource records
+ SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
+ SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
+
+ // replace port w/ NAT mapping if necessary
+ if (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(srs->NATinfo.ExternalPort))
+ srs->RR_SRV.resrec.rdata->u.srv.port = srs->NATinfo.ExternalPort;
+
+ // construct update packet
+ // set zone
+ ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
+ if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+
+ if (srs->TestForSelfConflict)
+ {
+ // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
+ if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) { err = mStatus_UnknownErr; goto exit; }
+ if (!(ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) { err = mStatus_UnknownErr; goto exit; }
}
- // free temp answers list
- cr = answers;
- while (cr) { fptr = cr; cr = cr->next; ufree(fptr); }
+ else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending)
+ {
+ // use SRV name for prereq
+ //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
- return;
-
- pkt_error:
- LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)",
- question->qname.c, question->qtype);
- return;
+ // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
+ // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
+ ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_SRV.resrec.name, kDNSQType_ANY);
+ if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+ }
+
+ //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
+ if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+
+ for (i = 0; i < srs->NumSubTypes; i++)
+ if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+
+ if (srs->state == regState_UpdatePending) // we're updating the txt record
+ {
+ AuthRecord *txt = &srs->RR_TXT;
+ // delete old RData
+ SetNewRData(&txt->resrec, txt->OrigRData, txt->OrigRDLen);
+ if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_TXT.resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
+
+ // add new RData
+ SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
+ if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+ }
+ else
+ if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+
+ target = GetServiceTarget(m, srs);
+ if (!target)
+ {
+ debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
+ srs->state = regState_NoTarget;
+ return;
+ }
+
+ if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target))
+ {
+ AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target);
+ SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash
+ }
+
+ ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_SRV.resrec, srs->RR_SRV.resrec.rroriginalttl);
+ if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+
+ if (srs->srs_uselease)
+ { ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } }
+
+ if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending)
+ srs->state = regState_Pending;
+
+ srs->id = id;
+
+ if (srs->Private)
+ {
+ LogOperation("SendServiceRegistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
+ if (srs->tcp) LogMsg("SendServiceRegistration: Already have TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
+ else srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->ns, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
+ srs->RR_SRV.LastAPTime = m->timenow;
+ srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us
+ }
+ else
+ {
+ err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->ns, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
+ if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err);
+ SetRecordRetry(m, &srs->RR_SRV, err);
+ }
+
+ err = mStatus_NoError;
+
+exit:
+
+ if (err)
+ {
+ LogMsg("SendServiceRegistration - Error formatting message %d", err);
- malloc_error:
- LogMsg("ERROR: Malloc");
+ unlinkSRS(m, srs);
+ srs->state = regState_Unregistered;
+
+ mDNS_DropLockBeforeCallback();
+ srs->ServiceCallback(m, srs, err);
+ mDNS_ReclaimLockAfterCallback();
+ // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+ // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+ }
}
-mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
+mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp";
+mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp";
+
+mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
+
+#define ZoneDataSRV(X) (\
+ (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
+ (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \
+ (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"")
+
+// Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and
+// GetZoneData_QuestionCallback calls GetZoneData_StartQuery
+mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype);
+
+// GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed)
+mDNSexport void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
- const mDNSu8 *ptr;
- int i;
- LargeCacheRecord lcr;
- CacheRecord *cr = &lcr.r;
- mDNSBool goodbye, inKAList, followedCName = mDNSfalse;
- LLQ_Info *llqInfo = question->uDNS_info.llq;
- domainname origname;
- origname.c[0] = 0;
-
- if (question != m->uDNS_info.CurrentQuery)
- { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; }
+ ZoneData *zd = (ZoneData*)question->QuestionContext;
- question->uDNS_info.Answered = mDNStrue;
-
- ptr = LocateAnswers(msg, end);
- if (!ptr) goto pkt_error;
+ debugf("GetZoneData_QuestionCallback: %s %s", AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
+
+ if (!AddRecord) return; // Don't care about REMOVE events
+ if (AddRecord == QC_addnocache && answer->rdlength == 0) return; // Don't care about transient failure indications
+ if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs
- for (i = 0; i < msg->h.numAnswers; i++)
+ if (answer->rrtype == kDNSType_SOA)
+ {
+ debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer));
+ mDNS_StopQuery(m, question);
+ if (answer->rdlength)
+ {
+ AssignDomainName(&zd->ZoneName, answer->name);
+ zd->ZoneClass = answer->rrclass;
+ AssignDomainName(&zd->question.qname, &zd->ZoneName);
+ GetZoneData_StartQuery(m, zd, kDNSType_SRV);
+ }
+ else if (zd->CurrentSOA->c[0])
+ {
+ zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
+ AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+ GetZoneData_StartQuery(m, zd, kDNSType_SOA);
+ }
+ else
+ {
+ LogMsg("ERROR: GetZoneData_QuestionCallback - recursed to root label of %##s without finding SOA", zd->ChildName.c);
+ zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
+ mDNSPlatformMemFree(zd);
+ }
+ }
+ else if (answer->rrtype == kDNSType_SRV)
{
- ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ptr) goto pkt_error;
- if (ResourceRecordAnswersQuestion(&cr->resrec, question))
+ debugf("GetZoneData GOT SRV %s", RRDisplayString(m, answer));
+ mDNS_StopQuery(m, question);
+ if (!answer->rdlength && zd->ZonePrivate && zd->ZoneService != ZoneServiceQuery)
+ {
+ zd->ZonePrivate = mDNSfalse; // Causes ZoneDataSRV() to yield a different SRV name when building the query
+ GetZoneData_StartQuery(m, zd, kDNSType_SRV); // Try again, non-private this time
+ }
+ else
{
- if (cr->resrec.rrtype == kDNSType_CNAME)
+ if (answer->rdlength)
{
- if (followedCName) LogMsg("Error: multiple CNAME referals for question %##s", question->qname.c);
- else
- {
- debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c);
- AssignDomainName(&origname, &question->qname);
- AssignDomainName(&question->qname, &cr->resrec.rdata->u.name);
- question->qnamehash = DomainNameHashValue(&question->qname);
- followedCName = mDNStrue;
- i = -1; // restart packet answer matching
- ptr = LocateAnswers(msg, end);
- continue;
- }
+ AssignDomainName(&zd->Host, &answer->rdata->u.srv.target);
+ zd->Port = answer->rdata->u.srv.port;
+ AssignDomainName(&zd->question.qname, &zd->Host);
+ GetZoneData_StartQuery(m, zd, kDNSType_A);
}
-
- goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse;
- inKAList = kaListContainsAnswer(question, cr);
-
- if ((goodbye && !inKAList) || (!goodbye && inKAList)) continue; // list up to date
- if (!inKAList) addKnownAnswer(question, cr);
- if (goodbye) removeKnownAnswer(question, cr);
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- question->QuestionCallback(m, question, &cr->resrec, !goodbye);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- if (question != m->uDNS_info.CurrentQuery)
+ else
{
- debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
- return;
+ zd->ZonePrivate = mDNSfalse;
+ zd->Host.c[0] = 0;
+ zd->Port = zeroIPPort;
+ zd->Addr = zeroAddr;
+ zd->ZoneDataCallback(m, mStatus_NoError, zd);
+ mDNSPlatformMemFree(zd);
}
}
- else if (!followedCName || !SameDomainName(cr->resrec.name, &origname))
- LogMsg("Question %##s %X (%s) %##s unexpected answer %##s %X (%s)",
- question->qname.c, question->qnamehash, DNSTypeName(question->qtype), origname.c,
- cr->resrec.name->c, cr->resrec.namehash, DNSTypeName(cr->resrec.rrtype));
}
-
- if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
+ else if (answer->rrtype == kDNSType_A)
{
- deriveGoodbyes(m, msg, end,question);
- if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse;
+ debugf("GetZoneData GOT A %s", RRDisplayString(m, answer));
+ mDNS_StopQuery(m, question);
+ zd->Addr.type = mDNSAddrType_IPv4;
+ zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr;
+ zd->ZoneDataCallback(m, mStatus_NoError, zd);
+ mDNSPlatformMemFree(zd);
}
-
- // Our interval may be set lower to recover from failures -- now that we have an answer, fully back off retry.
- // If the server advertised an LLQ-specific port number then that implies that this zone
- // *wants* to support LLQs, so if the setup fails (e.g. because we are behind a NAT)
- // then we use a slightly faster polling rate to give slightly better user experience.
- if (llq && llqInfo->state == LLQ_Poll && llqInfo->servPort.NotAnInteger) question->ThisQInterval = LLQ_POLL_INTERVAL;
- else if (question->ThisQInterval < MAX_UCAST_POLL_INTERVAL) question->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
- return;
-
- pkt_error:
- LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)",
- question->qname.c, question->qtype);
- return;
}
-mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
+// GetZoneData_StartQuery is called from normal client context (lock not held, or client callback)
+mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype)
{
- (void)context; // unused
- pktResponseHndlr(m, msg, end, question, mDNSfalse);
+ if (qtype == kDNSType_SRV)
+ {
+ LogOperation("lookupDNSPort %##s", ZoneDataSRV(zd));
+ AssignDomainName(&zd->question.qname, ZoneDataSRV(zd));
+ AppendDomainName(&zd->question.qname, &zd->ZoneName);
+ }
+
+ zd->question.ThisQInterval = -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
+ zd->question.InterfaceID = mDNSInterface_Any;
+ zd->question.Target = zeroAddr;
+ //zd->question.qname.c[0] = 0; // Already set
+ zd->question.qtype = qtype;
+ zd->question.qclass = kDNSClass_IN;
+ zd->question.LongLived = mDNSfalse;
+ zd->question.ExpectUnique = mDNStrue;
+ zd->question.ForceMCast = mDNSfalse;
+ zd->question.ReturnIntermed = mDNStrue;
+ zd->question.QuestionCallback = GetZoneData_QuestionCallback;
+ zd->question.QuestionContext = zd;
+
+ //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private);
+ return(mDNS_StartQuery(m, &zd->question));
}
-mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context)
+// StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
+mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
{
- (void)context; // unused
- pktResponseHndlr(m, msg, end, question, mDNStrue);
+ DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, name);
+ int initialskip = (AuthInfo && AuthInfo->AutoTunnel) ? DomainNameLength(name) - DomainNameLength(&AuthInfo->domain) : 0;
+ ZoneData *zd = (ZoneData*)mDNSPlatformMemAllocate(sizeof(ZoneData));
+ if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL; }
+ mDNSPlatformMemZero(zd, sizeof(ZoneData));
+ AssignDomainName(&zd->ChildName, name);
+ zd->ZoneService = target;
+ zd->CurrentSOA = (domainname *)(&zd->ChildName.c[initialskip]);
+ zd->ZoneName.c[0] = 0;
+ zd->ZoneClass = 0;
+ zd->Host.c[0] = 0;
+ zd->Port = zeroIPPort;
+ zd->Addr = zeroAddr;
+ zd->ZonePrivate = AuthInfo ? mDNStrue : mDNSfalse;
+ zd->ZoneDataCallback = callback;
+ zd->ZoneDataContext = ZoneDataContext;
+
+ zd->question.QuestionContext = zd;
+ AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+
+ mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
+ GetZoneData_StartQuery(m, zd, kDNSType_SOA);
+ mDNS_ReclaimLockAfterCallback();
+
+ return zd;
}
-mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname)
+// if LLQ NAT context unreferenced, delete the mapping
+mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m)
{
- LargeCacheRecord lcr;
- const mDNSu8 *ptr;
- mStatus err = mStatus_NoError;
- int i;
-
- ptr = LocateAdditionals(msg, end);
- if (!ptr) goto finish;
-
- for (i = 0; i < msg->h.numAdditionals; i++)
+ NATTraversalInfo *n = m->NATTraversals;
+ DNSQuestion *q;
+
+ while (n)
{
- ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
- if (!ptr) goto finish;
- if (lcr.r.resrec.rrtype == kDNSType_TSIG)
+ NATTraversalInfo *current = n;
+ n = n->next;
+ if (current->clientCallback == LLQNatMapComplete)
{
- mDNSu32 macsize;
- mDNSu8 *rd = lcr.r.resrec.rdata->u.data;
- mDNSu8 *rdend = rd + MaximumRDSize;
- int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name);
-
- if (rd + alglen > rdend) goto finish;
- rd += alglen; // algorithm name
- if (rd + 6 > rdend) goto finish;
- rd += 6; // 48-bit timestamp
- if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
- rd += sizeof(mDNSOpaque16); // fudge
- if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
- macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
- rd += sizeof(mDNSOpaque16); // MAC size
- if (rd + macsize > rdend) goto finish;
- rd += macsize;
- if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
- rd += sizeof(mDNSOpaque16); // orig id
- if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
- err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code
-
- if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; }
- else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; }
- else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; }
- else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
- goto finish;
+ for (q = m->Questions; q; q = q->next) if (&q->NATInfoUDP == current) break;
+ if (!q) mDNS_StopNATOperation_internal(m, current);
}
}
-
- finish:
- return err;
}
-mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - host name and interface management
+#endif
+
+// Called in normal client context (lock not held)
+mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
{
- (void)msg; // currently unused, needed for TSIG errors
- if (!rcode) return mStatus_NoError;
- else if (rcode == kDNSFlag1_RC_YXDomain)
- {
- debugf("name in use: %##s", displayname->c);
- return mStatus_NameConflict;
- }
- else if (rcode == kDNSFlag1_RC_Refused)
- {
- LogMsg("Update %##s refused", displayname->c);
- return mStatus_Refused;
- }
- else if (rcode == kDNSFlag1_RC_NXRRSet)
- {
- LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
- return mStatus_NoSuchRecord;
- }
- else if (rcode == kDNSFlag1_RC_NotAuth)
+ ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext;
+ LogOperation("SRVNatMap complete %.4a %u %u TTL %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease);
+
+ if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
+ if (!n->NATLease) return;
+
+ if (n->Result)
{
- // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
- mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
- if (!tsigerr)
+ HostnameInfo *hi = m->Hostnames;
+ while (hi)
{
- LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
- return mStatus_UnknownErr;
+ if (hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh) break;
+ else hi = hi->next;
}
- else return tsigerr;
- }
- else if (rcode == kDNSFlag1_RC_FmtErr)
- {
- mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
- if (!tsigerr)
+
+ if (hi)
{
- LogMsg("Format Error: %##s", displayname->c);
- return mStatus_UnknownErr;
+ debugf("Port map failed for service %##s - using IPv6 service target", srs->RR_SRV.resrec.name->c);
+ mDNS_StopNATOperation(m, &srs->NATinfo);
+ goto register_service;
}
- else return tsigerr;
+ else srs->state = regState_NATError;
}
+
+ register_service:
+ mDNS_Lock(m);
+ if (!mDNSIPv4AddressIsZero(srs->ns.ip.v4))
+ SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update
else
{
- LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
- return mStatus_UnknownErr;
+ // SHOULD NEVER HAPPEN!
+ LogOperation("ERROR: CompleteSRVNatMap called but srs->ns.ip.v4 is zero!");
+ srs->state = regState_FetchingZoneData;
+ if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one
+ srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs);
}
+ mDNS_Unlock(m);
}
-mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs, mStatus err)
+mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
{
- mDNSBool InvokeCallback = mDNSfalse;
- uDNS_RegInfo *info = &srs->uDNS_info;
- NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
- ExtraResourceRecord **e = &srs->Extras;
- AuthRecord *txt = &srs->RR_TXT;
- uDNS_RegInfo *txtInfo = &txt->uDNS_info;
- switch (info->state)
- {
- case regState_Pending:
- if (err == mStatus_NameConflict && !info->TestForSelfConflict)
- {
- info->TestForSelfConflict = mDNStrue;
- debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
- SendServiceRegistration(m, srs);
- return;
- }
- else if (info->TestForSelfConflict)
- {
- info->TestForSelfConflict = mDNSfalse;
- if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
- if (err) info->state = regState_Unregistered;
- else info->state = regState_Registered;
- InvokeCallback = mDNStrue;
- break;
- }
- else if (err == mStatus_UnknownErr && info->lease)
- {
- LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
- info->lease = mDNSfalse;
- SendServiceRegistration(m, srs);
- return;
- }
- else
- {
- if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); info->state = regState_Unregistered; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
- else info->state = regState_Registered;
- InvokeCallback = mDNStrue;
- break;
- }
- case regState_Refresh:
- if (err)
- {
- LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
- InvokeCallback = mDNStrue;
- info->state = regState_Unregistered;
- }
- else info->state = regState_Registered;
- break;
- case regState_DeregPending:
- if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
- if (info->SRVChanged)
- {
- info->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
- break;
- }
- err = mStatus_MemFree;
- InvokeCallback = mDNStrue;
- if (nat)
- {
- if (nat->state == NATState_Deleted) { info->NATinfo = mDNSNULL; FreeNATInfo(m, nat); } // deletion copmleted
- else nat->reg.ServiceRegistration = mDNSNULL; // allow mapping deletion to continue
- }
- info->state = regState_Unregistered;
- break;
- case regState_DeregDeferred:
- if (err)
- {
- debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
- err = mStatus_MemFree;
- InvokeCallback = mDNStrue;
- info->state = regState_Unregistered;
- break;
- }
- else
- {
- debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
- info->state = regState_Registered;
- SendServiceDeregistration(m, srs);
- return;
- }
- case regState_UpdatePending:
- if (err)
- {
- LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
- info->state = regState_Unregistered;
- InvokeCallback = mDNStrue;
- }
- else
- {
- info->state = regState_Registered;
- // deallocate old RData
- if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData);
- SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
- txtInfo->OrigRData = mDNSNULL;
- txtInfo->InFlightRData = mDNSNULL;
- }
- break;
- case regState_FetchingZoneData:
- case regState_Registered:
- case regState_Cancelled:
- case regState_Unregistered:
- case regState_NATMap:
- case regState_NoTarget:
- case regState_ExtraQueued:
- case regState_NATError:
- LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
- srs->RR_SRV.resrec.name->c, info->state, err);
- err = mStatus_UnknownErr;
- }
-
- if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
- {
- if (InvokeCallback)
- {
- info->ClientCallbackDeferred = mDNStrue;
- info->DeferredStatus = err;
- }
- info->SRVChanged = mDNSfalse;
- UpdateSRV(m, srs);
- return;
- }
-
- while (*e)
- {
- uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
- if (einfo->state == regState_ExtraQueued)
- {
- if (info->state == regState_Registered && !err)
- {
- // extra resource record queued for this service - copy zone info and register
- AssignDomainName(&einfo->zone, &info->zone);
- einfo->ns = info->ns;
- einfo->port = info->port;
- einfo->lease = info->lease;
- sendRecordRegistration(m, &(*e)->r);
- e = &(*e)->next;
- }
- else if (err && einfo->state != regState_Unregistered)
- {
- // unlink extra from list
- einfo->state = regState_Unregistered;
- *e = (*e)->next;
- }
- else e = &(*e)->next;
- }
- else e = &(*e)->next;
- }
+ mDNSu8 *p = srs->RR_PTR.resrec.name->c;
+ if (p[0]) p += 1 + p[0];
+
+ if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP;
+ else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP;
+ else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; }
+ srs->NATinfo.IntPort = srs->RR_SRV.resrec.rdata->u.srv.port;
+ srs->NATinfo.RequestedPort = srs->RR_SRV.resrec.rdata->u.srv.port;
+ srs->NATinfo.NATLease = 0; // Request default lease
+ srs->NATinfo.clientCallback = CompleteSRVNatMap;
+ srs->NATinfo.clientContext = srs;
+ mDNS_StartNATOperation_internal(m, &srs->NATinfo);
+ return;
- srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc.
- if (info->state == regState_Unregistered) unlinkSRS(m, srs);
- else if (txtInfo->QueuedRData && info->state == regState_Registered)
- {
- if (InvokeCallback)
- {
- // if we were supposed to give a client callback, we'll do it after we update the primary txt record
- info->ClientCallbackDeferred = mDNStrue;
- info->DeferredStatus = err;
- }
- info->state = regState_UpdatePending;
- txtInfo->InFlightRData = txtInfo->QueuedRData;
- txtInfo->InFlightRDLen = txtInfo->QueuedRDLen;
- info->OrigRData = txt->resrec.rdata;
- info->OrigRDLen = txt->resrec.rdlength;
- txtInfo->QueuedRData = mDNSNULL;
- SendServiceRegistration(m, srs);
- return;
- }
-
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- if (InvokeCallback) srs->ServiceCallback(m, srs, err);
- else if (info->ClientCallbackDeferred)
- {
- info->ClientCallbackDeferred = mDNSfalse;
- srs->ServiceCallback(m, srs, info->DeferredStatus);
- }
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- // NOTE: do not touch structures after calling ServiceCallback
+ error:
+ if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one
+ srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs);
}
-mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
+// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
+mDNSexport void ServiceRegistrationZoneDataComplete(mDNS *const m, mStatus err, const ZoneData *zoneData)
{
- uDNS_RegInfo *info = &rr->uDNS_info;
- mDNSBool InvokeCallback = mDNStrue;
+ ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext;
- if (info->state == regState_UpdatePending)
- {
- if (err)
- {
- LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
- info->state = regState_Unregistered;
- }
- else
- {
- debugf("Update record %##s - success", rr->resrec.name->c);
- info->state = regState_Registered;
- // deallocate old RData
- if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, info->OrigRData);
- SetNewRData(&rr->resrec, info->InFlightRData, info->InFlightRDLen);
- info->OrigRData = mDNSNULL;
- info->InFlightRData = mDNSNULL;
- }
- }
+ if (m->mDNS_busy != m->mDNS_reentrancy)
+ LogMsg("ServiceRegistrationZoneDataComplete: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+ srs->nta = mDNSNULL;
+
+ if (err) goto error;
+ if (!zoneData) { LogMsg("ERROR: ServiceRegistrationZoneDataComplete invoked with NULL result and no error"); goto error; }
+
+ if (srs->RR_SRV.resrec.rrclass != zoneData->ZoneClass)
+ { LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c); goto error; }
- if (info->state == regState_DeregPending)
+ // cache zone data
+ AssignDomainName(&srs->zone, &zoneData->ZoneName);
+ srs->ns.type = mDNSAddrType_IPv4;
+ srs->ns = zoneData->Addr;
+ if (!mDNSIPPortIsZero(zoneData->Port))
{
- debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
- if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
- rr->resrec.name->c, rr->resrec.rrtype, err);
- err = mStatus_MemFree;
- info->state = regState_Unregistered;
+ srs->SRSUpdatePort = zoneData->Port;
+ srs->Private = zoneData->ZonePrivate;
}
-
- if (info->state == regState_DeregDeferred)
+ else
{
- if (err)
- {
- LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
- rr->resrec.name->c, rr->resrec.rrtype, err);
- info->state = regState_Unregistered;
- }
- debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
- info->state = regState_Registered;
- uDNS_DeregisterRecord(m, rr);
- return;
+ debugf("Update port not advertised via SRV - guessing port 53, no lease option");
+ srs->SRSUpdatePort = UnicastDNSPort;
+ srs->srs_uselease = mDNSfalse;
}
- if (info->state == regState_Pending || info->state == regState_Refresh)
+ LogOperation("ServiceRegistrationZoneDataComplete %#a %d %#a %d", &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4), &srs->ns, mDNSAddrIsRFC1918(&srs->ns));
+
+ if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) &&
+ mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->ns) &&
+ srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
{
- if (!err)
- {
- info->state = regState_Registered;
- if (info->state == regState_Refresh) InvokeCallback = mDNSfalse;
- }
- else
- {
- if (info->lease && err == mStatus_UnknownErr)
- {
- LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
- info->lease = mDNSfalse;
- sendRecordRegistration(m, rr);
- return;
- }
- LogMsg("Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err);
- info->state = regState_Unregistered;
- }
- }
-
- if (info->state == regState_Unregistered) unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
- else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc.
-
- if (info->QueuedRData && info->state == regState_Registered)
- {
- info->state = regState_UpdatePending;
- info->InFlightRData = info->QueuedRData;
- info->InFlightRDLen = info->QueuedRDLen;
- info->OrigRData = rr->resrec.rdata;
- info->OrigRDLen = rr->resrec.rdlength;
- info->QueuedRData = mDNSNULL;
- sendRecordRegistration(m, rr);
- return;
+ srs->state = regState_NATMap;
+ LogOperation("ServiceRegistrationZoneDataComplete StartSRVNatMap");
+ StartSRVNatMap(m, srs);
}
-
- if (InvokeCallback)
+ else
{
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+ mDNS_Lock(m);
+ SendServiceRegistration(m, srs);
+ mDNS_Unlock(m);
}
- }
+ return;
+
+error:
+ unlinkSRS(m, srs);
+ srs->state = regState_Unregistered;
+ // Don't need to do the mDNS_DropLockBeforeCallback stuff here, because this code is
+ // *already* being invoked in the right callback context, with mDNS_reentrancy correctly incremented.
+ srs->ServiceCallback(m, srs, err);
+ // CAUTION: MUST NOT do anything more with rr after calling srs->ServiceCallback(), because the client's callback function
+ // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+ }
-mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info)
+mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
{
- LargeCacheRecord lcr;
- const mDNSu8 *ptr;
- int i;
- mDNSu32 lease = 0;
- mDNSs32 expire;
-
- ptr = LocateAdditionals(msg, end);
+ mDNSOpaque16 id;
+ mDNSu8 *ptr = m->omsg.data;
+ mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+ mStatus err = mStatus_UnknownErr;
+ mDNSu32 i;
- if (info->lease && (ptr = LocateAdditionals(msg, end)))
+ id = mDNS_NewMessageID(m);
+ InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
+
+ // put zone
+ ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
+ if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err = mStatus_UnknownErr; goto exit; }
+
+ if (!(ptr = putDeleteAllRRSets(&m->omsg, ptr, srs->RR_SRV.resrec.name))) { err = mStatus_UnknownErr; goto exit; } // this deletes SRV, TXT, and Extras
+ if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_PTR.resrec))) { err = mStatus_UnknownErr; goto exit; }
+ for (i = 0; i < srs->NumSubTypes; i++)
+ if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->SubTypes[i].resrec))) { err = mStatus_UnknownErr; goto exit; }
+
+ srs->id = id;
+ srs->state = regState_DeregPending;
+
+ if (srs->Private)
{
- for (i = 0; i < msg->h.numAdditionals; i++)
- {
- ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
- if (!ptr) break;
- if (lcr.r.resrec.rrtype == kDNSType_OPT)
- {
- if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue;
- if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
- lease = lcr.r.resrec.rdata->u.opt.OptData.lease;
- break;
- }
- }
+ LogOperation("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
+ if (srs->tcp) LogMsg("SendServiceDeregistration: Already have TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
+ else srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->ns, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
+ srs->RR_SRV.LastAPTime = m->timenow;
+ srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us
}
-
- if (lease > 0)
+ else
{
- expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
- if (info->state == regState_UpdatePending)
- // if updating individual record, the service record set may expire sooner
- { if (expire - info->expire < 0) info->expire = expire; }
- else info->expire = expire;
+ err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->ns, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
+ if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto exit; }
+ SetRecordRetry(m, &srs->RR_SRV, err);
}
- else info->lease = mDNSfalse;
- }
-mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- NATTraversalInfo *ptr = u->NATTraversals;
- NATOp_t op;
-
- // check length, version, opcode
- if (len < sizeof(NATPortMapReply) && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
- if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; }
- op = pkt[1];
- if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
+ err = mStatus_NoError;
+
+exit:
- while (ptr)
+ if (err)
{
- if ((ptr->state == NATState_Request || ptr->state == NATState_Refresh) && (ptr->op | NATMAP_RESPONSE_MASK) == op)
- if (ptr->ReceiveResponse(ptr, m, pkt, len)) break; // note callback may invalidate ptr if it return value is non-zero
- ptr = ptr->next;
+ unlinkSRS(m, srs);
+ srs->state = regState_Unregistered;
}
}
-mDNSlocal const domainname *DNSRelayTestQuestion = (domainname*)
- "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
- "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
-
-// Returns mDNStrue if response was handled
-mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
- const mDNSAddr *const srcaddr, const mDNSInterfaceID InterfaceID)
+// Called with lock held
+mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
{
- const mDNSu8 *ptr = msg->data;
- DNSQuestion q;
- DNSServer *s;
- mDNSu32 result = 0;
- mDNSBool found = mDNSfalse;
+ ExtraResourceRecord *e;
- // 1. Find out if this is an answer to one of our test questions
- if (msg->h.numQuestions != 1) return(mDNSfalse);
- ptr = getQuestion(msg, ptr, end, InterfaceID, &q);
- if (!ptr) return(mDNSfalse);
- if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse);
- if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse);
+ // Target change if:
+ // We have a target and were previously waiting for one, or
+ // We had a target and no longer do, or
+ // The target has changed
- // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
- // else, if the DNS relay gave us an error or no-answer response, it passed our test
- if ((msg->h.flags.b[1] & kDNSFlag1_RC) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
- result = DNSServer_Failed;
- else
- result = DNSServer_Passed;
+ domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
+ const domainname *const nt = GetServiceTarget(m, srs);
+ const domainname *const newtarget = nt ? nt : (domainname*)"";
+ mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget);
+ mDNSBool HaveZoneData = !mDNSIPv4AddressIsZero(srs->ns.ip.v4);
- // 3. Find occurrences of this server in our list, and mark them appropriately
- for (s = m->uDNS_info.Servers; s; s = s->next)
- if (mDNSSameAddress(srcaddr, &s->addr) && s->teststate != result)
- { s->teststate = result; found = mDNStrue; }
+ // Nat state change if:
+ // We were behind a NAT, and now we are behind a new NAT, or
+ // We're not behind a NAT but our port was previously mapped to a different public port
+ // We were not behind a NAT and now we are
- // 4. Assuming we found the server in question in our list (don't want to risk being victim of a deliberate DOS attack here)
- // log a message to let the user know why Wide-Area Service Discovery isn't working
- if (found && result == DNSServer_Failed)
- LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a.", srcaddr);
+ mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
+ mDNSBool NowBehindNAT = (!mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->ns));
+ mDNSBool WereBehindNAT = (srs->NATinfo.clientContext != mDNSNULL);
+ mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port)); // I think this is always false -- SC Sept 07
+ mDNSBool NATChanged = (!WereBehindNAT && NowBehindNAT) || (!NowBehindNAT && PortWasMapped);
- return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doens't need to process this packet further
- }
+ LogOperation("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowBehindNAT %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
+ srs->RR_SRV.resrec.name->c, newtarget,
+ TargetChanged, HaveZoneData, mDNSVal16(port), NowBehindNAT, WereBehindNAT, PortWasMapped, NATChanged);
-mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
- const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr,
- const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
- {
- DNSQuestion *qptr;
- AuthRecord *rptr;
- ServiceRecordSet *sptr;
- mStatus err = mStatus_NoError;
- uDNS_GlobalInfo *u = &m->uDNS_info;
-
- mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
- mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
- mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
- mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC);
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
- mDNSs32 timenow = mDNSPlatformTimeNow(m);
-
- // unused
- (void)dstaddr;
- (void)dstport;
- (void)InterfaceID;
-
- if (QR_OP == StdR)
+ if (!TargetChanged && !NATChanged) return;
+
+ switch(srs->state)
{
- // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
- // LLQ Responses over TCP not currently supported
- if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return;
-
- if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, InterfaceID)) return;
-
- for (qptr = u->ActiveQueries; qptr; qptr = qptr->next)
- {
- //!!!KRS we should have a hashtable, hashed on message id
- if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
+ case regState_FetchingZoneData:
+ case regState_DeregPending:
+ case regState_DeregDeferred:
+ case regState_Unregistered:
+ case regState_NATMap:
+ case regState_ExtraQueued:
+ // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
+ // or is in the process of, or has already been, deregistered
+ return;
+
+ case regState_Pending:
+ case regState_Refresh:
+ case regState_UpdatePending:
+ // let the in-flight operation complete before updating
+ srs->SRVUpdateDeferred = mDNStrue;
+ return;
+
+ case regState_NATError:
+ if (!NATChanged) return;
+ // if nat changed, register if we have a target (below)
+
+ case regState_NoTarget:
+ if (newtarget->c[0])
{
- if (timenow - (qptr->LastQTime + RESPONSE_WINDOW) > 0)
- { debugf("uDNS_ReceiveMsg - response received after maximum allowed window. Discarding"); return; }
- if (msg->h.flags.b[0] & kDNSFlag0_TC)
- { hndlTruncatedAnswer(qptr, srcaddr, m); return; }
+ debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
+ if (!HaveZoneData)
+ {
+ srs->state = regState_FetchingZoneData;
+ if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one
+ srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs);
+ }
else
{
- u->CurrentQuery = qptr;
- qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context);
- u->CurrentQuery = mDNSNULL;
- // Note: responseCallback can invalidate qptr
- return;
+ if (srs->NATinfo.clientContext && (NATChanged || !NowBehindNAT))
+ {
+ mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+ srs->NATinfo.clientContext = mDNSNULL;
+ }
+ if (NATChanged && NowBehindNAT && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
+ { srs->state = regState_NATMap; StartSRVNatMap(m, srs); }
+ else SendServiceRegistration(m, srs);
}
}
+ return;
+
+ case regState_Registered:
+ // target or nat changed. deregister service. upon completion, we'll look for a new target
+ debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c);
+ for (e = srs->Extras; e; e = e->next) e->r.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered
+ srs->SRVChanged = mDNStrue;
+ SendServiceDeregistration(m, srs);
+ return;
+
+ default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
+ }
+ }
+
+// Called with lock held
+mDNSlocal void UpdateSRVRecords(mDNS *m)
+ {
+ if (CurrentServiceRecordSet)
+ LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
+ CurrentServiceRecordSet = m->ServiceRegistrations;
+
+ while (CurrentServiceRecordSet)
+ {
+ ServiceRecordSet *s = CurrentServiceRecordSet;
+ CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
+ UpdateSRV(m, s);
+ }
+ }
+
+// Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
+mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+
+// Called in normal client context (lock not held)
+mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
+ {
+ HostnameInfo *h = (HostnameInfo *)n->clientContext;
+
+ if (!h) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; }
+
+ if (!n->Result)
+ {
+ if (mDNSIPv4AddressIsZero(n->ExternalAddress) || mDNSv4AddrIsRFC1918(&n->ExternalAddress)) return;
+
+ if (h->arv4.resrec.RecordType)
+ {
+ if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return; // If address unchanged, do nothing
+ LogMsg("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress);
+ mDNS_Deregister(m, &h->arv4); // mStatus_MemFree callback will re-register with new address
+ }
+ else
+ {
+ LogMsg("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress);
+ h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
+ h->arv4.resrec.rdata->u.ipv4 = n->ExternalAddress;
+ mDNS_Register(m, &h->arv4);
}
}
- if (QR_OP == UpdateR)
+ }
+
+// register record or begin NAT traversal
+mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h)
+ {
+ if (!mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4) && h->arv4.resrec.RecordType == kDNSRecordTypeUnregistered)
{
- for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next)
+ mDNS_SetupResourceRecord(&h->arv4, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, HostnameCallback, h);
+ AssignDomainName(&h->arv4.namestorage, &h->fqdn);
+ h->arv4.resrec.rdata->u.ipv4 = m->AdvertisedV4.ip.v4;
+ h->arv4.state = regState_Unregistered;
+ if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4))
{
- if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
- {
- err = checkUpdateResult(sptr->RR_SRV.resrec.name, rcode, m, msg, end);
- if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
- hndlServiceUpdateReply(m, sptr, err);
- return;
- }
+ // If we already have a NAT query active, stop it and restart it to make sure we get another callback
+ if (h->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &h->natinfo);
+ h->natinfo.Protocol = 0;
+ h->natinfo.IntPort = zeroIPPort;
+ h->natinfo.RequestedPort = zeroIPPort;
+ h->natinfo.NATLease = 0;
+ h->natinfo.clientCallback = hostnameGetPublicAddressCallback;
+ h->natinfo.clientContext = h;
+ mDNS_StartNATOperation_internal(m, &h->natinfo);
}
- for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
+ else
{
- if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
- {
- err = checkUpdateResult(rptr->resrec.name, rcode, m, msg, end);
- if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);
- hndlRecordUpdateReply(m, rptr, err);
- return;
- }
+ LogMsg("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4);
+ h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique;
+ mDNS_Register_internal(m, &h->arv4);
}
}
- debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
+
+ if (!mDNSIPv6AddressIsZero(m->AdvertisedV6.ip.v6) && h->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
+ {
+ mDNS_SetupResourceRecord(&h->arv6, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeKnownUnique, HostnameCallback, h);
+ AssignDomainName(&h->arv6.namestorage, &h->fqdn);
+ h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6;
+ h->arv6.state = regState_Unregistered;
+ LogMsg("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6);
+ mDNS_Register_internal(m, &h->arv6);
+ }
}
-// lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful
-mDNSlocal DNSServer *GetServerForName(uDNS_GlobalInfo *u, const domainname *name)
- {
- DNSServer *curmatch = mDNSNULL, *p = u->Servers;
- int i, curmatchlen = -1;
- int ncount = name ? CountLabels(name) : 0;
+mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+ {
+ HostnameInfo *hi = (HostnameInfo *)rr->RecordContext;
- while (p)
+ if (result == mStatus_MemFree)
{
- int scount = CountLabels(&p->domain);
- if (scount <= ncount && scount > curmatchlen)
+ if (hi)
{
- // only inspect if server's domain is longer than current best match and shorter than the name itself
- const domainname *tail = name;
- for (i = 0; i < ncount - scount; i++)
- tail = (domainname *)(tail->c + 1 + tail->c[0]); // find "tail" (scount labels) of name
- if (SameDomainName(tail, &p->domain)) { curmatch = p; curmatchlen = scount; }
+ // If we're still in the Hostnames list, update to new address
+ HostnameInfo *i;
+ LogOperation("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi, rr, ARDisplayString(m, rr));
+ for (i = m->Hostnames; i; i = i->next)
+ if (rr == &i->arv4 || rr == &i->arv6)
+ { mDNS_Lock(m); AdvertiseHostname(m, i); mDNS_Unlock(m); return; }
+
+ // Else, we're not still in the Hostnames list, so free the memory
+ if (hi->arv4.resrec.RecordType == kDNSRecordTypeUnregistered &&
+ hi->arv6.resrec.RecordType == kDNSRecordTypeUnregistered)
+ {
+ if (hi->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &hi->natinfo);
+ hi->natinfo.clientContext = mDNSNULL;
+ mDNSPlatformMemFree(hi); // free hi when both v4 and v6 AuthRecs deallocated
+ }
}
- p = p->next;
+ return;
}
- return(curmatch);
- }
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Query Routines
-#endif
+ if (result)
+ {
+ // don't unlink or free - we can retry when we get a new address/router
+ if (rr->resrec.rrtype == kDNSType_A)
+ LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
+ else
+ LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
+ if (!hi) { mDNSPlatformMemFree(rr); return; }
+ if (rr->state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
-#define sameID(x,y) mDNSPlatformMemSame(x,y,8)
+ if (hi->arv4.state == regState_Unregistered &&
+ hi->arv6.state == regState_Unregistered)
+ {
+ // only deliver status if both v4 and v6 fail
+ rr->RecordContext = (void *)hi->StatusContext;
+ if (hi->StatusCallback)
+ hi->StatusCallback(m, rr, result); // client may NOT make API calls here
+ rr->RecordContext = (void *)hi;
+ }
+ return;
+ }
-mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question)
- {
- ubzero(msg, sizeof(msg));
- InitializeDNSMessage(&msg->h, question->uDNS_info.id, uQueryFlags);
- }
+ // register any pending services that require a target
+ mDNS_Lock(m);
+ UpdateSRVRecords(m);
+ mDNS_Unlock(m);
-mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question)
- {
- initializeQuery(msg, question);
+ // Deliver success to client
+ if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
+ if (rr->resrec.rrtype == kDNSType_A)
+ LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4);
+ else
+ LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6);
- *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
- if (!*endPtr)
- {
- LogMsg("ERROR: Unicast query out of space in packet");
- return mStatus_UnknownErr;
- }
- return mStatus_NoError;
+ rr->RecordContext = (void *)hi->StatusContext;
+ if (hi->StatusCallback)
+ hi->StatusCallback(m, rr, result); // client may NOT make API calls here
+ rr->RecordContext = (void *)hi;
}
-mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
+mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
- AuthRecord rr;
- ResourceRecord *opt = &rr.resrec;
- rdataOpt *optRD;
-
- //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
- if (includeQuestion)
+ const domainname *pktname = &answer->rdata->u.name;
+ domainname *storedname = &m->StaticHostname;
+ HostnameInfo *h = m->Hostnames;
+
+ (void)question;
+
+ debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
+ if (AddRecord && !SameDomainName(pktname, storedname))
{
- ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
- if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
+ AssignDomainName(storedname, pktname);
+ while (h)
+ {
+ if (h->arv4.state == regState_FetchingZoneData || h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap ||
+ h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending)
+ {
+ // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds
+ m->NextSRVUpdate = NonZeroTime(m->timenow + (5 * mDNSPlatformOneSecond));
+ return;
+ }
+ h = h->next;
+ }
+ mDNS_Lock(m);
+ UpdateSRVRecords(m);
+ mDNS_Unlock(m);
}
- // locate OptRR if it exists, set pointer to end
- // !!!KRS implement me
+ else if (!AddRecord && SameDomainName(pktname, storedname))
+ {
+ mDNS_Lock(m);
+ storedname->c[0] = 0;
+ UpdateSRVRecords(m);
+ mDNS_Unlock(m);
+ }
+ }
-
- // format opt rr (fields not specified are zero-valued)
- ubzero(&rr, sizeof(AuthRecord));
- mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
- opt->rdlength = LLQ_OPT_RDLEN;
- opt->rdestimate = LLQ_OPT_RDLEN;
+// Called with lock held
+mDNSlocal void GetStaticHostname(mDNS *m)
+ {
+ char buf[MAX_REVERSE_MAPPING_NAME_V4];
+ DNSQuestion *q = &m->ReverseMap;
+ mDNSu8 *ip = m->AdvertisedV4.ip.v4.b;
+ mStatus err;
- optRD = &rr.resrec.rdata->u.opt;
- optRD->opt = kDNSOpt_LLQ;
- optRD->optlen = LLQ_OPTLEN;
- umemcpy(&optRD->OptData.llq, data, sizeof(*data));
- ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0);
- if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; }
+ if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, q);
- return ptr;
- }
+ m->StaticHostname.c[0] = 0;
+ if (mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4)) return;
+ mDNSPlatformMemZero(q, sizeof(*q));
+ // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
+ mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
+ if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
-
-mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index)
- {
- LargeCacheRecord lcr;
- int i;
- const mDNSu8 *ptr;
-
- ubzero(&lcr, sizeof(lcr));
-
- ptr = LocateAdditionals(msg, end);
- if (!ptr) return mDNSfalse;
-
- // find the last additional
- for (i = 0; i < msg->h.numAdditionals; i++)
-// { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
-//!!!KRS workaround for LH server bug, which puts OPT as first additional
- { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }
- if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse;
- if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_RDLEN) return mDNSfalse; // rdata too small
- umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(*llq)), sizeof(*llq));
- return mDNStrue;
+ q->InterfaceID = mDNSInterface_Any;
+ q->Target = zeroAddr;
+ q->qtype = kDNSType_PTR;
+ q->qclass = kDNSClass_IN;
+ q->LongLived = mDNSfalse;
+ q->ExpectUnique = mDNSfalse;
+ q->ForceMCast = mDNSfalse;
+ q->ReturnIntermed = mDNStrue;
+ q->QuestionCallback = FoundStaticHostname;
+ q->QuestionContext = mDNSNULL;
+
+ err = mDNS_StartQuery_internal(m, q);
+ if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err);
}
-mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q)
- {
- LLQ_Info *qInfo;
- LLQOptData pktData;
-
- qInfo = q->uDNS_info.llq;
- if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; }
- if (pktData.llqOp != kLLQOp_Refresh) return;
- if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch. Discarding"); return; }
- if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; }
-
- qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond);
- qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
-
- qInfo->origLease = pktData.lease;
- qInfo->state = LLQ_Established;
+mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
+ {
+ HostnameInfo **ptr = &m->Hostnames;
+
+ LogOperation("mDNS_AddDynDNSHostName %##s", fqdn);
+
+ while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
+ if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
+
+ // allocate and format new address record
+ *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
+ if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
+
+ mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+ AssignDomainName(&(*ptr)->fqdn, fqdn);
+ (*ptr)->arv4.state = regState_Unregistered;
+ (*ptr)->arv6.state = regState_Unregistered;
+ (*ptr)->StatusCallback = StatusCallback;
+ (*ptr)->StatusContext = StatusContext;
+
+ AdvertiseHostname(m, *ptr);
}
-mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
+mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
{
- DNSMessage msg;
- mDNSu8 *end;
- LLQOptData llq;
- LLQ_Info *info = q->uDNS_info.llq;
- mStatus err;
- mDNSs32 timenow;
+ HostnameInfo **ptr = &m->Hostnames;
+
+ LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn);
- timenow = mDNSPlatformTimeNow(m);
- if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) ||
- info->expire - timenow < 0)
+ while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next;
+ if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
+ else
{
- LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q->qname.c, kLLQ_DEF_RETRY/60);
- info->state = LLQ_Retry;
- info->retry = mDNSPlatformTimeNow(m) + kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
- info->deriveRemovesOnResume = mDNStrue;
- return;
- //!!!KRS handle this - periodically try to re-establish
+ HostnameInfo *hi = *ptr;
+ // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);"
+ // below could free the memory, and we have to make sure we don't touch hi fields after that.
+ mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered;
+ mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered;
+ if (f4) LogOperation("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn);
+ if (f6) LogOperation("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn);
+ *ptr = (*ptr)->next; // unlink
+ if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal);
+ if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
+ // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
}
+ UpdateSRVRecords(m);
+ }
- llq.vers = kLLQ_Vers;
- llq.llqOp = kLLQOp_Refresh;
- llq.err = LLQErr_NoError;
- umemcpy(llq.id, info->id, 8);
- llq.lease = lease;
+// Currently called without holding the lock
+// Maybe we should change that?
+mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
+ {
+ mDNSBool v4Changed, v6Changed, RouterChanged;
- initializeQuery(&msg, q);
- end = putLLQ(&msg, msg.data, q, &llq, mDNStrue);
- if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
-
- err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
- if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
+ if (m->mDNS_busy != m->mDNS_reentrancy)
+ LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
- if (info->state == LLQ_Established) info->ntries = 1;
- else info->ntries++;
- info->state = LLQ_Refresh;
- q->LastQTime = timenow;
- info->retry = (info->expire - q->LastQTime) / 2;
- }
+ if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type. Discarding. %#a", v4addr); return; }
+ if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type. Discarding. %#a", v6addr); return; }
+ if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router. Discarding. %#a", router); return; }
-mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
- {
- DNSMessage ack;
- mDNSu8 *ackEnd = ack.data;
- mStatus err;
- LLQOptData opt;
+ mDNS_Lock(m);
+
+ if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL;
+
+ v4Changed = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr);
+ v6Changed = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr);
+ RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4, router ? router->ip.v4 : zerov4Addr);
+
+ if (v4addr && (v4Changed || RouterChanged))
+ debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m->AdvertisedV4, v4addr);
+
+ if (v4addr) m->AdvertisedV4 = *v4addr; else m->AdvertisedV4.ip.v4 = zerov4Addr;
+ if (v6addr) m->AdvertisedV6 = *v6addr; else m->AdvertisedV6.ip.v6 = zerov6Addr;
+ if (router) m->Router = *router; else m->Router .ip.v4 = zerov4Addr;
+ // setting router to zero indicates that nat mappings must be reestablished when router is reset
+
+ if (v4Changed || RouterChanged || v6Changed)
+ {
+ HostnameInfo *i;
+ LogOperation("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a",
+ v4Changed ? "v4Changed " : "",
+ RouterChanged ? "RouterChanged " : "",
+ v6Changed ? "v6Changed " : "", v4addr, v6addr, router);
+
+ for (i = m->Hostnames; i; i = i->next)
+ {
+ LogOperation("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c);
- (void)InterfaceID; // unused
-
- // find Opt RR, verify correct ID
- if (!getLLQAtIndex(m, msg, end, &opt, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse; }
- if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata"); return mDNSfalse; }
- if (!sameID(opt.id, q->uDNS_info.llq->id)) { return mDNSfalse; }
- if (opt.llqOp != kLLQOp_Event) { if (!q->uDNS_info.llq->ntries) LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; }
-
- // invoke response handler
- m->uDNS_info.CurrentQuery = q;
- q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context);
- if (m->uDNS_info.CurrentQuery != q) return mDNStrue;
+ if (i->arv4.resrec.RecordType > kDNSRecordTypeDeregistering &&
+ !mDNSSameIPv4Address(i->arv4.resrec.rdata->u.ipv4, m->AdvertisedV4.ip.v4))
+ {
+ LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4));
+ mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal);
+ }
- // format and send ack
- InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags);
- ackEnd = putLLQ(&ack, ack.data, mDNSNULL, &opt, mDNSfalse);
- if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putLLQ"); return mDNSfalse; }
- err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL);
- if (err) debugf("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err);
- return mDNStrue;
- }
+ if (i->arv6.resrec.RecordType > kDNSRecordTypeDeregistering &&
+ !mDNSSameIPv6Address(i->arv6.resrec.rdata->u.ipv6, m->AdvertisedV6.ip.v6))
+ {
+ LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6));
+ mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal);
+ }
+ // AdvertiseHostname will only register new address records.
+ // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them.
+ AdvertiseHostname(m, i);
+ }
+
+ if (v4Changed || RouterChanged)
+ {
+ m->ExternalAddress = zerov4Addr;
+ m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
+ m->retryGetAddr = m->timenow;
+ m->NextScheduledNATOp = m->timenow;
+ ClearUPnPState(m);
+ }
+ UpdateSRVRecords(m);
+ GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address
+ }
-mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
+ mDNS_Unlock(m);
+ }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Incoming Message Processing
+#endif
+
+mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const domainname *const displayname)
{
- LLQ_Info *info = q->uDNS_info.llq;
-
- if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; }
- if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
- info->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
- info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2);
-
- info->origLease = llq->lease;
- info->state = LLQ_Established;
-
- q->uDNS_info.responseCallback = llqResponseHndlr;
- llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
- return;
+ const mDNSu8 *ptr;
+ mStatus err = mStatus_NoError;
+ int i;
- error:
- info->state = LLQ_Error;
+ ptr = LocateAdditionals(msg, end);
+ if (!ptr) goto finish;
+
+ for (i = 0; i < msg->h.numAdditionals; i++)
+ {
+ ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
+ if (!ptr) goto finish;
+ if (m->rec.r.resrec.rrtype == kDNSType_TSIG)
+ {
+ mDNSu32 macsize;
+ mDNSu8 *rd = m->rec.r.resrec.rdata->u.data;
+ mDNSu8 *rdend = rd + m->rec.r.resrec.rdlength;
+ int alglen = DomainNameLengthLimit(&m->rec.r.resrec.rdata->u.name, rdend);
+ if (alglen > MAX_DOMAIN_NAME) goto finish;
+ rd += alglen; // algorithm name
+ if (rd + 6 > rdend) goto finish;
+ rd += 6; // 48-bit timestamp
+ if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+ rd += sizeof(mDNSOpaque16); // fudge
+ if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+ macsize = mDNSVal16(*(mDNSOpaque16 *)rd);
+ rd += sizeof(mDNSOpaque16); // MAC size
+ if (rd + macsize > rdend) goto finish;
+ rd += macsize;
+ if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+ rd += sizeof(mDNSOpaque16); // orig id
+ if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
+ err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code
+
+ if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; }
+ else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; }
+ else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; }
+ else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
+ goto finish;
+ }
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ }
+
+ finish:
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ return err;
}
-mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq)
+mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displayname, const mDNSu8 rcode, const DNSMessage *const msg, const mDNSu8 *const end)
{
- LLQ_Info *info = q->uDNS_info.llq;
- DNSMessage response;
- mDNSu8 *responsePtr = response.data;
- mStatus err;
- LLQOptData llqBuf;
- mDNSs32 timenow = mDNSPlatformTimeNow(m);
-
- if (info->ntries++ == kLLQ_MAX_TRIES)
+ (void)msg; // currently unused, needed for TSIG errors
+ if (!rcode) return mStatus_NoError;
+ else if (rcode == kDNSFlag1_RC_YXDomain)
{
- LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes",
- kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
- info->state = LLQ_Retry;
- info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond);
- // !!!KRS give a callback error in these cases?
- return;
+ debugf("name in use: %##s", displayname->c);
+ return mStatus_NameConflict;
}
-
- if (!llq)
+ else if (rcode == kDNSFlag1_RC_Refused)
{
- llq = &llqBuf;
- llq->vers = kLLQ_Vers;
- llq->llqOp = kLLQOp_Setup;
- llq->err = LLQErr_NoError;
- umemcpy(llq->id, info->id, 8);
- llq->lease = info->origLease;
+ LogMsg("Update %##s refused", displayname->c);
+ return mStatus_Refused;
}
+ else if (rcode == kDNSFlag1_RC_NXRRSet)
+ {
+ LogMsg("Reregister refused (NXRRSET): %##s", displayname->c);
+ return mStatus_NoSuchRecord;
+ }
+ else if (rcode == kDNSFlag1_RC_NotAuth)
+ {
+ // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too
+ mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
+ if (!tsigerr)
+ {
+ LogMsg("Permission denied (NOAUTH): %##s", displayname->c);
+ return mStatus_UnknownErr;
+ }
+ else return tsigerr;
+ }
+ else if (rcode == kDNSFlag1_RC_FmtErr)
+ {
+ mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
+ if (!tsigerr)
+ {
+ LogMsg("Format Error: %##s", displayname->c);
+ return mStatus_UnknownErr;
+ }
+ else return tsigerr;
+ }
+ else
+ {
+ LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
+ return mStatus_UnknownErr;
+ }
+ }
- q->LastQTime = timenow;
- info->retry = timenow + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond);
-
- if (constructQueryMsg(&response, &responsePtr, q)) goto error;
- responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse);
- if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; }
-
- err = mDNSSendDNSMessage(m, &response, responsePtr, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
- if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err);
- // on error, we procede as normal and retry after the appropriate interval
+// Called with lock held
+mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
+ {
+ mDNSu8 *ptr = m->omsg.data;
+ mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+ mStatus err = mStatus_UnknownErr;
- return;
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
- error:
- info->state = LLQ_Error;
- }
+ rr->RequireGoodbye = mDNStrue;
+ rr->id = mDNS_NewMessageID(m);
+ InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags);
+ // set zone
+ ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+ if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+ if (rr->state == regState_UpdatePending)
+ {
+ // delete old RData
+ SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen);
+ if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
-mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q)
- {
- LLQ_Info *info = q->uDNS_info.llq;
- mDNSs32 timenow = mDNSPlatformTimeNow(m);
- switch(llq->err)
- {
- case LLQErr_NoError: break;
- case LLQErr_ServFull:
- LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s. Retry in %lu sec", q->qname.c, llq->lease);
- info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
- info->state = LLQ_Retry;
- simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL); // get available answers
- info->deriveRemovesOnResume = mDNStrue;
- case LLQErr_Static:
- info->state = LLQ_Static;
- LogMsg("LLQ %##s: static", q->qname.c);
- simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL);
- return;
- case LLQErr_FormErr:
- LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c);
- goto error;
- case LLQErr_BadVers:
- LogMsg("ERROR: hndlRequestChallenge - received BadVers from server");
- goto error;
- case LLQErr_UnknownErr:
- LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c);
- goto error;
- default:
- LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c);
- goto error;
+ // add new RData
+ SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
+ if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
}
- if (info->origLease != llq->lease)
- debugf("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease);
-
- // cache expiration in case we go to sleep before finishing setup
- info->origLease = llq->lease;
- info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond);
+ else
+ {
+ if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
+ {
+ // KnownUnique: Delete any previous value
+ ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype);
+ if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+ }
- // update state
- info->state = LLQ_SecondaryRequest;
- umemcpy(info->id, llq->id, 8);
- info->ntries = 0; // first attempt to send response
+ else if (rr->resrec.RecordType != kDNSRecordTypeShared)
+ {
+ ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
+ if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+ }
- sendChallengeResponse(m, q, llq);
- return;
+ ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
+ if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+ }
+ if (rr->uselease)
+ {
+ ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+ }
- error:
- info->state = LLQ_Error;
- }
+ if (rr->Private)
+ {
+ LogOperation("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
+ if (rr->tcp) LogMsg("SendRecordRegistration: Already have TCP connection for %s", ARDisplayString(m, rr));
+ else rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
+ rr->LastAPTime = m->timenow;
+ rr->ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us
+ }
+ else
+ {
+ err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+ if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err);
+ SetRecordRetry(m, rr, err);
+ }
+ if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending)
+ rr->state = regState_Pending;
-// response handler for initial and secondary setup responses
-mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext)
- {
- DNSQuestion pktQuestion;
- LLQOptData llq;
- const mDNSu8 *ptr = pktMsg->data;
- LLQ_Info *info = q->uDNS_info.llq;
- mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC);
+ err = mStatus_NoError;
- (void)clientContext; // unused
-
- if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll;
-
- ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion);
- if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll; }
- if (!SameDomainName(&q->qname, &pktQuestion.qname))
- { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c); goto poll; }
-
- if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; }
- if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; }
- if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers); goto poll; }
-
- if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
- if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
- LogMsg("recvSetupResponse - bad state %d", info->state);
-
- poll:
- info->state = LLQ_Poll;
- q->uDNS_info.responseCallback = llqResponseHndlr;
- info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
- info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
- }
+exit:
-mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
- {
- DNSMessage msg;
- mDNSu8 *end;
- LLQOptData llqData;
- DNSQuestion *q = info->question;
- mStatus err = mStatus_NoError;
- mDNSs32 timenow = mDNSPlatformTimeNow(m);
- uDNS_GlobalInfo *u = &m->uDNS_info;
-
- if (IsPrivateV4Addr(&u->AdvertisedV4))
+ if (err)
{
- if (!u->LLQNatInfo)
+ LogMsg("SendRecordRegistration: Error formatting message %d", err);
+
+ if (rr->state != regState_Unregistered)
{
- info->state = LLQ_NatMapWait;
- StartLLQNatMap(m);
- return;
+ UnlinkAuthRecord(m, rr);
+ rr->state = regState_Unregistered;
}
- if (u->LLQNatInfo->state == NATState_Error) goto poll;
- if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy)
- { info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; }
- info->NATMap = mDNStrue; // this llq references the global llq nat mapping
- }
-
- if (info->ntries++ >= kLLQ_MAX_TRIES)
- {
- debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
- goto poll;
- }
-
- // set llq rdata
- llqData.vers = kLLQ_Vers;
- llqData.llqOp = kLLQOp_Setup;
- llqData.err = LLQErr_NoError;
- ubzero(llqData.id, 8);
- llqData.lease = kLLQ_DefLease;
-
- initializeQuery(&msg, q);
- end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue);
- if (!end)
- {
- LogMsg("ERROR: startLLQHandshake - putLLQ");
- info->state = LLQ_Error;
- return;
+
+ mDNS_DropLockBeforeCallback();
+ if (rr->RecordCallback)
+ rr->RecordCallback(m, rr, err);
+ mDNS_ReclaimLockAfterCallback();
+ // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+ // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
}
+ }
+
+// Called with lock held
+mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mStatus err)
+ {
+ mDNSBool InvokeCallback = mDNSfalse;
+ ExtraResourceRecord **e = &srs->Extras;
+ AuthRecord *txt = &srs->RR_TXT;
+
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
- if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future
+ switch (srs->state)
{
- err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL);
- if (err) debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err);
- // on error, we procede as normal and retry after the appropriate interval
+ case regState_Pending:
+ if (err == mStatus_NameConflict && !srs->TestForSelfConflict)
+ {
+ srs->TestForSelfConflict = mDNStrue;
+ debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
+ SendServiceRegistration(m, srs);
+ return;
+ }
+ else if (srs->TestForSelfConflict)
+ {
+ srs->TestForSelfConflict = mDNSfalse;
+ if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
+ if (err) srs->state = regState_Unregistered;
+ else srs->state = regState_Registered;
+ InvokeCallback = mDNStrue;
+ break;
+ }
+ else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort))
+ {
+ LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
+ srs->srs_uselease = mDNSfalse;
+ SendServiceRegistration(m, srs);
+ return;
+ }
+ else
+ {
+ //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
+ if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); srs->state = regState_Unregistered; }
+ else srs->state = regState_Registered;
+ InvokeCallback = mDNStrue;
+ break;
+ }
+ case regState_Refresh:
+ if (err)
+ {
+ LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
+ InvokeCallback = mDNStrue;
+ srs->state = regState_Unregistered;
+ }
+ else srs->state = regState_Registered;
+ break;
+ case regState_DeregPending:
+ if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
+ if (srs->SRVChanged)
+ {
+ srs->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
+ break;
+ }
+ err = mStatus_MemFree;
+ InvokeCallback = mDNStrue;
+ if (srs->NATinfo.clientContext)
+ {
+ // deletion completed
+ mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+ srs->NATinfo.clientContext = mDNSNULL;
+ }
+ srs->state = regState_Unregistered;
+ break;
+ case regState_DeregDeferred:
+ if (err)
+ {
+ debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
+ err = mStatus_MemFree;
+ InvokeCallback = mDNStrue;
+ srs->state = regState_Unregistered;
+ break;
+ }
+ else
+ {
+ debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
+ srs->state = regState_Registered;
+ SendServiceDeregistration(m, srs);
+ return;
+ }
+ case regState_UpdatePending:
+ if (err)
+ {
+ LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
+ srs->state = regState_Unregistered;
+ InvokeCallback = mDNStrue;
+ }
+ else
+ {
+ srs->state = regState_Registered;
+ // deallocate old RData
+ if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
+ SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
+ txt->OrigRData = mDNSNULL;
+ txt->InFlightRData = mDNSNULL;
+ }
+ break;
+ case regState_FetchingZoneData:
+ case regState_Registered:
+ case regState_Unregistered:
+ case regState_NATMap:
+ case regState_NoTarget:
+ case regState_ExtraQueued:
+ case regState_NATError:
+ LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.",
+ srs->RR_SRV.resrec.name->c, srs->state, err);
+ err = mStatus_UnknownErr;
+ default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
}
-
- // update question/info state
- info->state = LLQ_InitialRequest;
- info->origLease = kLLQ_DefLease;
- info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
- q->LastQTime = timenow;
- q->uDNS_info.responseCallback = recvSetupResponse;
- q->uDNS_info.internal = mDNStrue;
- return;
-
- poll:
- info->question->uDNS_info.responseCallback = llqResponseHndlr;
- info->state = LLQ_Poll;
- info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
- info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
- }
-// wrapper for startLLQHandshake, invoked by async op callback
-mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result)
- {
- LLQ_Info *info = (LLQ_Info *)llqInfo;
- const zoneData_t *zoneInfo = mDNSNULL;
-
- // check state first to make sure it is OK to touch question object
- if (info->state == LLQ_Cancelled)
+ if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
{
- // StopQuery was called while we were getting the zone info
- debugf("startLLQHandshake - LLQ Cancelled.");
- info->question = mDNSNULL; // question may be deallocated
- ufree(info);
+ LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
+ if (InvokeCallback)
+ {
+ srs->ClientCallbackDeferred = mDNStrue;
+ srs->DeferredStatus = err;
+ }
+ srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
+ UpdateSRV(m, srs);
return;
}
- if (!info->question)
- { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; }
-
- if (info->state != LLQ_GetZoneInfo)
- { LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; }
-
- if (err)
- { LogMsg("ERROR: startLLQHandshakeCallback %##s invoked with error code %ld", info->question->qname.c, err); goto poll; }
-
- if (!result)
- { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; }
-
- zoneInfo = &result->zoneData;
-
- if (!zoneInfo->llqPort.NotAnInteger)
- { debugf("LLQ port lookup failed - reverting to polling"); info->servPort.NotAnInteger = 0; goto poll; }
-
- // cache necessary zone data
- info->servAddr = zoneInfo->primaryAddr;
- info->servPort = zoneInfo->llqPort;
- info->ntries = 0;
-
- if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended;
- else startLLQHandshake(m, info, mDNSfalse);
- return;
-
- poll:
- info->question->uDNS_info.responseCallback = llqResponseHndlr;
- info->state = LLQ_Poll;
- info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll
- info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
- return;
-
- error:
- info->state = LLQ_Error;
- }
-
-mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question)
- {
- LLQ_Info *info;
- mStatus err = mStatus_NoError;
-
- // allocate / init info struct
- info = umalloc(sizeof(LLQ_Info));
- if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; }
- ubzero(info, sizeof(LLQ_Info));
- info->state = LLQ_GetZoneInfo;
-
- // link info/question
- info->question = question;
- question->uDNS_info.llq = info;
-
- question->uDNS_info.responseCallback = llqResponseHndlr;
-
- err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info);
- if (err)
+ while (*e)
{
- LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err);
- info->question = mDNSNULL;
- ufree(info);
- question->uDNS_info.llq = mDNSNULL;
- return err;
- }
-
- LinkActiveQuestion(&m->uDNS_info, question);
- return err;
- }
-
-mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID)
- {
- DNSQuestion pktQ, *q;
- uDNS_GlobalInfo *u = &m->uDNS_info;
- const mDNSu8 *ptr = msg->data;
- LLQ_Info *llqInfo;
-
- if (!msg->h.numQuestions) return mDNSfalse;
-
- ptr = getQuestion(msg, ptr, end, 0, &pktQ);
- if (!ptr) return mDNSfalse;
- pktQ.uDNS_info.id = msg->h.id;
-
- q = u->ActiveQueries;
- while (q)
- {
- llqInfo = q->uDNS_info.llq;
- if (q->LongLived &&
- llqInfo &&
- q->qnamehash == pktQ.qnamehash &&
- q->qtype == pktQ.qtype &&
- SameDomainName(&q->qname, &pktQ.qname))
+ if ((*e)->r.state == regState_ExtraQueued)
{
- u->CurrentQuery = q;
- if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))
- { if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; }
- else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger)
+ if (srs->state == regState_Registered && !err)
{
- if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers)
- { recvRefreshReply(m, msg, end, q); return mDNStrue; }
- if (llqInfo->state < LLQ_Static)
- {
- if ((llqInfo->state != LLQ_InitialRequest && llqInfo->state != LLQ_SecondaryRequest) || mDNSSameAddress(srcaddr, &llqInfo->servAddr))
- { q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; }
- }
+ // extra resource record queued for this service - copy zone srs and register
+ AssignDomainName(&(*e)->r.zone, &srs->zone);
+ (*e)->r.UpdateServer = srs->ns;
+ (*e)->r.UpdatePort = srs->SRSUpdatePort;
+ (*e)->r.uselease = srs->srs_uselease;
+ SendRecordRegistration(m, &(*e)->r);
+ e = &(*e)->next;
+ }
+ else if (err && (*e)->r.state != regState_Unregistered)
+ {
+ // unlink extra from list
+ (*e)->r.state = regState_Unregistered;
+ *e = (*e)->next;
}
+ else e = &(*e)->next;
}
- q = q->next;
+ else e = &(*e)->next;
}
- return mDNSfalse;
- }
-
-mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u)
- {
- DNSQuestion *q;
- for (q = u->ActiveQueries; q; q = q->next)
+ srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc.
+ if (srs->state == regState_Unregistered) unlinkSRS(m, srs);
+ else if (txt->QueuedRData && srs->state == regState_Registered)
{
- if (q == question)
+ if (InvokeCallback)
{
- if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&question->qname))
- LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p",
- question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID);
- return mDNStrue;
+ // if we were supposed to give a client callback, we'll do it after we update the primary txt record
+ srs->ClientCallbackDeferred = mDNStrue;
+ srs->DeferredStatus = err;
}
+ srs->state = regState_UpdatePending;
+ txt->InFlightRData = txt->QueuedRData;
+ txt->InFlightRDLen = txt->QueuedRDLen;
+ txt->OrigRData = txt->resrec.rdata;
+ txt->OrigRDLen = txt->resrec.rdlength;
+ txt->QueuedRData = mDNSNULL;
+ SendServiceRegistration(m, srs);
+ return;
}
- return mDNSfalse;
- }
-// stopLLQ happens IN ADDITION to stopQuery
-mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
- {
- LLQ_Info *info = question->uDNS_info.llq;
- (void)m; // unused
-
- if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; }
- if (!info) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; }
-
- switch (info->state)
+ mDNS_DropLockBeforeCallback();
+ if (InvokeCallback)
+ srs->ServiceCallback(m, srs, err);
+ else if (srs->ClientCallbackDeferred)
{
- case LLQ_UnInit:
- LogMsg("ERROR: stopLLQ - state LLQ_UnInit");
- //!!!KRS should we unlink info<->question here?
- return;
- case LLQ_GetZoneInfo:
- case LLQ_SuspendDeferred:
- info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op
- info->state = LLQ_Cancelled;
- return;
- case LLQ_Established:
- case LLQ_Refresh:
- // refresh w/ lease 0
- sendLLQRefresh(m, question, 0);
- goto end;
- default:
- debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
- goto end;
+ srs->ClientCallbackDeferred = mDNSfalse;
+ srs->ServiceCallback(m, srs, srs->DeferredStatus);
}
-
- end:
- if (info->NATMap) info->NATMap = mDNSfalse;
- CheckForUnreferencedLLQMapping(m);
- info->question = mDNSNULL;
- ufree(info);
- question->uDNS_info.llq = mDNSNULL;
- question->LongLived = mDNSfalse;
+ mDNS_ReclaimLockAfterCallback();
+ // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+ // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
}
-mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question)
+// Called with lock held
+mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
{
- uDNS_GlobalInfo *u = &m->uDNS_info;
- DNSQuestion *qptr, *prev = mDNSNULL;
- CacheRecord *ka;
-
- qptr = u->ActiveQueries;
- while (qptr)
- {
- if (qptr == question)
- {
- if (question->LongLived && question->uDNS_info.llq)
- stopLLQ(m, question);
- if (m->uDNS_info.CurrentQuery == question)
- m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next;
- while (question->uDNS_info.knownAnswers)
- {
- ka = question->uDNS_info.knownAnswers;
- question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next;
- ufree(ka);
- }
- if (prev) prev->next = question->next;
- else u->ActiveQueries = question->next;
- return mStatus_NoError;
- }
- prev = qptr;
- qptr = qptr->next;
- }
- LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c);
- return mStatus_UnknownErr;
- }
-
-mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- //!!!KRS we should check if the question is already in our activequestion list
- if (!ValidateDomainName(&question->qname))
- {
- LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- return mStatus_Invalid;
- }
-
- question->next = mDNSNULL;
- question->qnamehash = DomainNameHashValue(&question->qname); // to do quick domain name comparisons
- question->uDNS_info.id = newMessageID(u);
- question->uDNS_info.Answered = mDNSfalse;
-
- // break here if its and LLQ
- if (question->LongLived) return startLLQ(m, question);
-
- question->ThisQInterval = INIT_UCAST_POLL_INTERVAL / 2;
- question->LastQTime = mDNSPlatformTimeNow(m) - question->ThisQInterval;
- // store the question/id in active question list
- question->uDNS_info.internal = internal;
- LinkActiveQuestion(u, question);
- question->uDNS_info.knownAnswers = mDNSNULL;
- LogOperation("uDNS startQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-
- return mStatus_NoError;
- }
-
-mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
- {
- ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo));
- question->uDNS_info.responseCallback = simpleResponseHndlr;
- question->uDNS_info.context = mDNSNULL;
- //LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- return startQuery(m, question, 0);
- }
-
-// explicitly set response handler
-mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
- {
- ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo));
- q->QuestionContext = hndlrContext;
- q->uDNS_info.responseCallback = callback;
- q->uDNS_info.context = hndlrContext;
- return startQuery(m, q, 1);
- }
-
-
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Domain -> Name Server Conversion
-#endif
-
-
-/* startGetZoneData
- *
- * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name,
- * i.e. the server to which update and LLQ requests will be sent for a given name. Once the address is
- * derived, it will be passed to the callback, along with a context pointer. If the zone cannot
- * be determined or if an error occurs, an all-zeros address will be passed and a message will be
- * written to the syslog.
- *
- * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined
- * by querying for the _dns-update._udp.<zone>. SRV record. Likewise, if the FindLLQPort arg is set,
- * the port on which the server accepts long lived queries is determined by querying for
- * _dns-llq._udp.<zone>. record. If either of these queries fail, or flags are not specified,
- * the llqPort and updatePort fields in the result structure are set to zero.
- *
- * Steps for deriving the zone name are as follows:
- *
- * Query for an SOA record for the required domain. If we don't get an answer (or an SOA in the Authority
- * section), we strip the leading label from the name and repeat, until we get an answer.
- *
- * The name of the SOA record is our enclosing zone. The mname field in the SOA rdata is the domain
- * name of the primary NS.
- *
- * We verify that there is an NS record with this zone for a name and the mname for its rdata.
- * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since
- * the NS query will get us address records in the additionals section, which we'd otherwise have to
- * explicitly query for.)
- *
- * We then query for the address record for this nameserver (if it is not in the addionals section of
- * the NS record response.)
- */
-
-
-// state machine types and structs
-//
+ mDNSBool InvokeCallback = mDNStrue;
-// state machine states
-typedef enum
- {
- init,
- lookupSOA,
- foundZone,
- lookupNS,
- foundNS,
- lookupA,
- foundA,
- lookupPort,
- foundPort,
- complete
- } ntaState;
-
-// state machine actions
-typedef enum
- {
- smContinue, // continue immediately to next state
- smBreak, // break until next packet/timeout
- smError // terminal error - cleanup and abort
- } smAction;
-
-typedef struct
- {
- domainname origName; // name we originally try to convert
- domainname *curSOA; // name we have an outstanding SOA query for
- ntaState state; // determines what we do upon receiving a packet
- mDNS *m;
- domainname zone; // left-hand-side of SOA record
- mDNSu16 zoneClass;
- domainname ns; // mname in SOA rdata, verified in confirmNS state
- mDNSv4Addr addr; // address of nameserver
- DNSQuestion question; // storage for any active question
- DNSQuestion extraQuestion; // additional storage
- mDNSBool questionActive; // if true, StopQuery() can be called on the question field
- mDNSBool findUpdatePort;
- mDNSBool findLLQPort;
- mDNSIPPort updatePort;
- mDNSIPPort llqPort;
- AsyncOpCallback *callback; // caller specified function to be called upon completion
- void *callbackInfo;
- } ntaContext;
-
-
-// function prototypes (for routines that must be used as fn pointers prior to their definitions,
-// and allows states to be read top-to-bottom in logical order)
-mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr);
-mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
-mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr);
-mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
-mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
-mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context);
-
-// initialization
-mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort,
- AsyncOpCallback callback, void *callbackInfo)
- {
- ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext));
- if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed"); return mStatus_NoMemoryErr; }
- ubzero(context, sizeof(ntaContext));
- AssignDomainName(&context->origName, name);
- context->state = init;
- context->m = m;
- context->callback = callback;
- context->callbackInfo = callbackInfo;
- context->findUpdatePort = findUpdatePort;
- context->findLLQPort = findLLQPort;
- getZoneData(m, mDNSNULL, mDNSNULL, mDNSNULL, context);
- return mStatus_NoError;
- }
-
-// state machine entry routine
-mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr)
- {
- AsyncOpResult result;
- ntaContext *context = (ntaContext*)contextPtr;
- smAction action;
-
- // unused
- (void)m;
- (void)question;
-
- // stop any active question
- if (context->questionActive)
- {
- uDNS_StopQuery(context->m, &context->question);
- context->questionActive = mDNSfalse;
- }
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
- if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain)
- {
- // rcode non-zero, non-nxdomain
- LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4);
- goto error;
- }
-
- switch (context->state)
- {
- case init:
- case lookupSOA:
- action = hndlLookupSOA(msg, end, context);
- if (action == smError) goto error;
- if (action == smBreak) return;
- case foundZone:
- case lookupNS:
- action = confirmNS(msg, end, context);
- if (action == smError) goto error;
- if (action == smBreak) return;
- case foundNS:
- case lookupA:
- action = lookupNSAddr(msg, end, context);
- if (action == smError) goto error;
- if (action == smBreak) return;
- case foundA:
- if (!context->findUpdatePort && !context->findLLQPort)
- {
- context->state = complete;
- break;
- }
- case lookupPort:
- action = hndlLookupPorts(msg, end, context);
- if (action == smError) goto error;
- if (action == smBreak) return;
- if (action == smContinue) context->state = complete;
- case foundPort:
- case complete: break;
- }
-
- if (context->state != complete)
- {
- LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state);
- goto error;
- }
-
- result.type = zoneDataResult;
- result.zoneData.primaryAddr.ip.v4 = context->addr;
- result.zoneData.primaryAddr.type = mDNSAddrType_IPv4;
- AssignDomainName(&result.zoneData.zoneName, &context->zone);
- result.zoneData.zoneClass = context->zoneClass;
- result.zoneData.llqPort = context->findLLQPort ? context->llqPort : zeroIPPort;
- result.zoneData.updatePort = context->findUpdatePort ? context->updatePort : zeroIPPort;
- context->callback(mStatus_NoError, context->m, context->callbackInfo, &result);
- goto cleanup;
-
-error:
- if (context && context->callback)
- context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);
-cleanup:
- if (context && context->questionActive)
+ if (rr->state == regState_UpdatePending)
{
- uDNS_StopQuery(context->m, &context->question);
- context->questionActive = mDNSfalse;
- }
- if (context) ufree(context);
- }
-
-mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
- {
- mStatus err;
- LargeCacheRecord lcr;
- ResourceRecord *rr = &lcr.r.resrec;
- DNSQuestion *query = &context->question;
- const mDNSu8 *ptr;
-
- if (msg)
- {
- // if msg contains SOA record in answer or authority sections, update context/state and return
- int i;
- ptr = LocateAnswers(msg, end);
- for (i = 0; i < msg->h.numAnswers; i++)
+ if (err)
{
- ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL"); return smError; }
- if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, rr->name))
- {
- processSOA(context, rr);
- return smContinue;
- }
+ LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
+ rr->state = regState_Unregistered;
}
- ptr = LocateAuthorities(msg, end);
- // SOA not in answers, check in authority
- for (i = 0; i < msg->h.numAuthorities; i++)
+ else
{
- ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth
- if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL"); return smError; }
- if (rr->rrtype == kDNSType_SOA)
- {
- processSOA(context, rr);
- return smContinue;
- }
+ debugf("Update record %##s - success", rr->resrec.name->c);
+ rr->state = regState_Registered;
+ // deallocate old RData
+ if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData);
+ SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
+ rr->OrigRData = mDNSNULL;
+ rr->InFlightRData = mDNSNULL;
}
}
- if (context->state != init && !context->curSOA->c[0])
- {
- // we've gone down to the root and have not found an SOA
- LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA",
- context->origName.c);
- return smError;
- }
-
- ubzero(query, sizeof(DNSQuestion));
- // chop off leading label unless this is our first try
- if (context->state == init) context->curSOA = &context->origName;
- else context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
-
- context->state = lookupSOA;
- AssignDomainName(&query->qname, context->curSOA);
- query->qtype = kDNSType_SOA;
- query->qclass = kDNSClass_IN;
- err = startInternalQuery(query, context->m, getZoneData, context);
- context->questionActive = mDNStrue;
- if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
-
- return smBreak; // break from state machine until we receive another packet
- }
-
-mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
- {
- AssignDomainName(&context->zone, rr->name);
- context->zoneClass = rr->rrclass;
- AssignDomainName(&context->ns, &rr->rdata->u.soa.mname);
- context->state = foundZone;
- }
-
+ if (rr->state == regState_DeregPending)
+ {
+ debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
+ if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
+ rr->resrec.name->c, rr->resrec.rrtype, err);
+ err = mStatus_MemFree;
+ rr->state = regState_Unregistered;
+ }
-mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
- {
- DNSQuestion *query = &context->question;
- mStatus err;
- LargeCacheRecord lcr;
- const ResourceRecord *const rr = &lcr.r.resrec;
- const mDNSu8 *ptr;
- int i;
-
- if (context->state == foundZone)
- {
- // we've just learned the zone. confirm that an NS record exists
- AssignDomainName(&query->qname, &context->zone);
- query->qtype = kDNSType_NS;
- query->qclass = kDNSClass_IN;
- err = startInternalQuery(query, context->m, getZoneData, context);
- context->questionActive = mDNStrue;
- if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err);
- context->state = lookupNS;
- return smBreak; // break from SM until we receive another packet
- }
- else if (context->state == lookupNS)
- {
- ptr = LocateAnswers(msg, end);
- for (i = 0; i < msg->h.numAnswers; i++)
+ if (rr->state == regState_DeregDeferred)
+ {
+ if (err)
{
- ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL"); return smError; }
- if (rr->rrtype == kDNSType_NS &&
- SameDomainName(&context->zone, rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
- {
- context->state = foundNS;
- return smContinue; // next routine will examine additionals section of A record
- }
+ LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
+ rr->resrec.name->c, rr->resrec.rrtype, err);
+ rr->state = regState_Unregistered;
}
- debugf("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
- return smError;
+ debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
+ rr->state = regState_Registered;
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+ return;
}
- else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; }
- }
-
-mDNSlocal smAction queryNSAddr(ntaContext *context)
- {
- mStatus err;
- DNSQuestion *query = &context->question;
-
- AssignDomainName(&query->qname, &context->ns);
- query->qtype = kDNSType_A;
- query->qclass = kDNSClass_IN;
- err = startInternalQuery(query, context->m, getZoneData, context);
- context->questionActive = mDNStrue;
- if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
- context->state = lookupA;
- return smBreak;
- }
-mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
- {
- const mDNSu8 *ptr;
- int i;
- LargeCacheRecord lcr;
- ResourceRecord *rr = &lcr.r.resrec;
-
- if (context->state == foundNS)
+ if (rr->state == regState_Pending || rr->state == regState_Refresh)
{
- // we just found the NS record - look for the corresponding A record in the Additionals section
- if (!msg->h.numAdditionals) return queryNSAddr(context);
- ptr = LocateAdditionals(msg, end);
- if (!ptr)
+ if (!err)
{
- LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals);
- return queryNSAddr(context);
+ rr->state = regState_Registered;
+ if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse;
}
else
{
- for (i = 0; i < msg->h.numAdditionals; i++)
+ if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort))
{
- ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ptr)
- {
- LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
- return queryNSAddr(context);
- }
- if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
- {
- context->addr = rr->rdata->u.ipv4;
- context->state = foundA;
- return smContinue;
- }
+ LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
+ rr->uselease = mDNSfalse;
+ SendRecordRegistration(m, rr);
+ return;
}
+ LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err);
+ rr->state = regState_Unregistered;
}
- // no A record in Additionals - query the server
- return queryNSAddr(context);
}
- else if (context->state == lookupA)
+
+ if (rr->state == regState_Unregistered) UnlinkAuthRecord(m, rr);
+ else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc.
+
+ if (rr->QueuedRData && rr->state == regState_Registered)
+ {
+ rr->state = regState_UpdatePending;
+ rr->InFlightRData = rr->QueuedRData;
+ rr->InFlightRDLen = rr->QueuedRDLen;
+ rr->OrigRData = rr->resrec.rdata;
+ rr->OrigRDLen = rr->resrec.rdlength;
+ rr->QueuedRData = mDNSNULL;
+ SendRecordRegistration(m, rr);
+ return;
+ }
+
+ if (InvokeCallback && rr->RecordCallback)
{
- ptr = LocateAnswers(msg, end);
- if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL"); return smError; }
- for (i = 0; i < msg->h.numAnswers; i++)
+ mDNS_DropLockBeforeCallback();
+ rr->RecordCallback(m, rr, err);
+ mDNS_ReclaimLockAfterCallback();
+ }
+ // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+ // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+ }
+
+mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len)
+ {
+ NATTraversalInfo *ptr;
+ NATAddrReply *AddrReply = (NATAddrReply *)pkt;
+ NATPortMapReply *PortMapReply = (NATPortMapReply *)pkt;
+ mDNSu32 nat_elapsed, our_elapsed;
+
+ // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes
+ if (!AddrReply->err && len < 8) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
+ if (AddrReply->vers != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt[0], NATMAP_VERS); return; }
+
+ // Read multi-byte numeric values (fields are identical in a NATPortMapReply)
+ AddrReply->err = (mDNSu16) ( (mDNSu16)pkt[2] << 8 | pkt[3]);
+ AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[7]);
+
+ nat_elapsed = AddrReply->upseconds - m->LastNATupseconds;
+ our_elapsed = (m->timenow - m->LastNATReplyLocalTime) / mDNSPlatformOneSecond;
+ LogOperation("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply->opcode, AddrReply->upseconds, nat_elapsed, our_elapsed);
+
+ // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
+ // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
+ // 2. We add a two-second safety margin to allow for rounding errors:
+ // -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds,
+ // but based on the values in the packet (2,7) the apparent difference is only 5 seconds
+ // -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval
+ // (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds)
+ if (AddrReply->upseconds < m->LastNATupseconds || nat_elapsed + 2 < our_elapsed - our_elapsed/8)
+ { LogMsg("NAT gateway %#a rebooted", &m->Router); RecreateNATMappings(m); }
+
+ m->LastNATupseconds = AddrReply->upseconds;
+ m->LastNATReplyLocalTime = m->timenow;
+ ClearUPnPState(m); // We know this is a NAT-PMP base station, so discard any prior UPnP state
+
+ if (AddrReply->opcode == NATOp_AddrResponse)
+ {
+ if (!AddrReply->err && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len); return; }
+ natTraversalHandleAddressReply(m, AddrReply->err, AddrReply->ExtAddr);
+ }
+ else if (AddrReply->opcode == NATOp_MapUDPResponse || AddrReply->opcode == NATOp_MapTCPResponse)
+ {
+ mDNSu8 Protocol = AddrReply->opcode & 0x7F;
+ if (!PortMapReply->err)
{
- ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
- if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
- {
- context->addr = rr->rdata->u.ipv4;
- context->state = foundA;
- return smContinue;
- }
+ if (len < sizeof(NATPortMapReply)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len); return; }
+ PortMapReply->NATRep_lease = (mDNSu32) ((mDNSu32)pkt[12] << 24 | (mDNSu32)pkt[13] << 16 | (mDNSu32)pkt[14] << 8 | pkt[15]);
}
- LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
- return smError;
+
+ for (ptr = m->NATTraversals; ptr; ptr=ptr->next)
+ if (ptr->Protocol == Protocol && mDNSSameIPPort(ptr->IntPort, PortMapReply->intport))
+ natTraversalHandlePortMapReply(m, ptr, InterfaceID, PortMapReply->err, PortMapReply->extport, PortMapReply->NATRep_lease);
}
- else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; }
+ else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; }
}
-
-mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port)
+
+// <rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
+// <rdar://problem/4288449> Add check to avoid crashing NAT gateways that have buggy DNS relay code
+//
+// We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries.
+// The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't,
+// the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to
+// be written assuming that a malicious attacker could send them any packet, properly-formed or not.
+// Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid
+// the queries that crash them.
+//
+// Some examples:
+//
+// 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes.
+// The query type does not need to be PTR -- the gateway will crash for any query type.
+// e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these.
+//
+// 2. Any query that results in a large response with the TC bit set.
+//
+// 3. Any PTR query that doesn't begin with four decimal numbers.
+// These gateways appear to assume that the only possible PTR query is a reverse-mapping query
+// (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four
+// labels are not all decimal numbers in the range 0-255, they handle that by crashing.
+// These gateways also ignore the remainder of the name following the four decimal numbers
+// -- whether or not it actually says in-addr.arpa, they just make up an answer anyway.
+//
+// The challenge therefore is to craft a query that will discern whether the DNS server
+// is one of these buggy ones, without crashing it. Furthermore we don't want our test
+// queries making it all the way to the root name servers, putting extra load on those
+// name servers and giving Apple a bad reputation. To this end we send this query:
+// dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa.
+//
+// The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1).
+// It will not yield a large response with the TC bit set, so it won't cause crash (2).
+// It starts with four decimal numbers, so it won't cause crash (3).
+// The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local
+// loopback address, and therefore the query will black-hole at the first properly-configured DNS server
+// it reaches, making it highly unlikely that this query will make it all the way to the root.
+//
+// Finally, the correct response to this query is NXDOMAIN or a similar error, but the
+// gateways that ignore the remainder of the name following the four decimal numbers
+// give themselves away by actually returning a result for this nonsense query.
+
+mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*)
+ "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest"
+ "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa";
+
+// Returns mDNStrue if response was handled
+mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
+ const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
{
- int i;
- LargeCacheRecord lcr;
- const mDNSu8 *ptr;
- DNSQuestion *q;
- mStatus err;
-
- if (context->state == lookupPort) // we've already issued the query
- {
- if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; }
- ptr = LocateAnswers(msg, end);
- for (i = 0; i < msg->h.numAnswers; i++)
+ const mDNSu8 *ptr = msg->data;
+ DNSQuestion q;
+ DNSServer *s;
+ mDNSu32 result = 0;
+
+ // 1. Find out if this is an answer to one of our test questions
+ if (msg->h.numQuestions != 1) return(mDNSfalse);
+ ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
+ if (!ptr) return(mDNSfalse);
+ if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse);
+ if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse);
+
+ // 2. If the DNS relay gave us a positive response, then it's got buggy firmware
+ // else, if the DNS relay gave us an error or no-answer response, it passed our test
+ if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0)
+ result = DNSServer_Failed;
+ else
+ result = DNSServer_Passed;
+
+ // 3. Find occurrences of this server in our list, and mark them appropriately
+ for (s = m->DNSServers; s; s = s->next)
+ if (mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port) && s->teststate != result)
{
- ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL"); return smError; }
- if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question))
+ DNSQuestion *q;
+ if (s->teststate != result)
{
- *port = lcr.r.resrec.rdata->u.srv.port;
- context->state = foundPort;
- return smContinue;
+ s->teststate = result;
+ if (result == DNSServer_Passed) LogOperation("DNS Server %#a:%d passed", srcaddr, mDNSVal16(srcport));
+ else LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d", srcaddr, mDNSVal16(srcport));
}
+ if (result == DNSServer_Passed) // Unblock any questions that were waiting for this result
+ for (q = m->Questions; q; q=q->next)
+ if (q->qDNSServer == s)
+ { q->LastQTime = m->timenow - q->ThisQInterval; m->NextScheduledQuery = m->timenow; }
}
- debugf("hndlLookupUpdatePort - no answer for type %s", portName);
- port->NotAnInteger = 0;
- context->state = foundPort;
- return smContinue;
- }
-
- // query the server for the update port for the zone
- context->state = lookupPort;
- q = &context->question;
- MakeDomainNameFromDNSNameString(&q->qname, portName);
- AppendDomainName(&q->qname, &context->zone);
- q->qtype = kDNSType_SRV;
- q->qclass = kDNSClass_IN;
- err = startInternalQuery(q, context->m, getZoneData, context);
- context->questionActive = mDNStrue;
- if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
- return smBreak; // break from state machine until we receive another packet
- }
-
-mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
- {
- smAction action;
-
- if (context->findUpdatePort && !context->updatePort.NotAnInteger)
- {
- action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort);
- if (action != smContinue) return action;
- }
- if (context->findLLQPort && !context->llqPort.NotAnInteger)
- return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort);
- return smContinue;
+ return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further
}
+// Called from mDNSCoreReceive with the lock held
+mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
+ {
+ DNSQuestion *qptr;
+ mStatus err = mStatus_NoError;
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Truncation Handling
-#endif
+ mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
+ mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
+ mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
+ mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC_Mask);
-typedef struct
- {
- DNSQuestion *question;
- DNSMessage *reply;
- mDNSu16 replylen;
- int nread;
- mDNS *m;
- } tcpInfo_t;
+ (void)srcport; // Unused
-// issue queries over a conected socket
-mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished)
- {
- mStatus err = 0;
- char msgbuf[356]; // 96 (hdr) + 256 (domain) + 4 (class/type)
- DNSMessage *msg;
- mDNSu8 *end;
- tcpInfo_t *info = (tcpInfo_t *)context;
- DNSQuestion *question = info->question;
- int n;
- mDNS *m = info->m;
+ debugf("uDNS_ReceiveMsg from %#-15a with "
+ "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+ srcaddr,
+ msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,",
+ msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
+ msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
+ msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
- mDNS_Lock(m);
-
- if (ConnectionEstablished)
+ if (QR_OP == StdR)
{
- // connection is established - send the message
- msg = (DNSMessage *)&msgbuf;
- err = constructQueryMsg(msg, &end, question);
- if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err); goto error; }
- err = mDNSSendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL);
- question->LastQTime = mDNSPlatformTimeNow(m);
- if (err) { debugf("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err); goto error; }
+ //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return;
+ if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, srcport)) return;
+ if (!mDNSOpaque16IsZero(msg->h.id))
+ for (qptr = m->Questions; qptr; qptr = qptr->next)
+ if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
+ {
+ if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
+ else if (qptr->tcp)
+ {
+ // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it
+ // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss)
+ // should take care of it but later we may want to look at handling this case explicitly
+ LogOperation("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr->qname.c, DNSTypeName(qptr->qtype));
+ mDNS_DropLockBeforeCallback();
+ tcpCallback(qptr->tcp->sock, qptr->tcp, mDNStrue, mStatus_NoError);
+ mDNS_ReclaimLockAfterCallback();
+ }
+ else qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, qptr, mDNSNULL, mDNSNULL);
+ }
}
- else
+
+ if (QR_OP == UpdateR && !mDNSOpaque16IsZero(msg->h.id))
{
- if (!info->nread)
+ mDNSu32 lease = GetPktLease(m, msg, end);
+ mDNSs32 expire = (m->timenow + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
+
+ if (CurrentServiceRecordSet)
+ LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
+ CurrentServiceRecordSet = m->ServiceRegistrations;
+
+ while (CurrentServiceRecordSet)
{
- // read msg len
- mDNSu8 lenbuf[2];
- n = mDNSPlatformReadTCP(sd, lenbuf, 2);
- if (n != 2)
+ ServiceRecordSet *sptr = CurrentServiceRecordSet;
+ CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
+
+ if (mDNSSameOpaque16(sptr->id, msg->h.id))
{
- LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
- goto error;
+ err = checkUpdateResult(m, sptr->RR_SRV.resrec.name, rcode, msg, end);
+ if (!err && sptr->srs_uselease && lease)
+ if (sptr->expire - expire >= 0 || sptr->state != regState_UpdatePending)
+ sptr->expire = expire;
+ hndlServiceUpdateReply(m, sptr, err);
+ CurrentServiceRecordSet = mDNSNULL;
+ return;
}
- info->replylen = (mDNSu16)((mDNSu16)lenbuf[0] << 8 | lenbuf[1]);
- if (info->replylen < sizeof(DNSMessageHeader))
- { LogMsg("ERROR: conQueryCallback - length too short (%d bytes)", info->replylen); goto error; }
- info->reply = umalloc(info->replylen);
- if (!info->reply) { LogMsg("ERROR: conQueryCallback - malloc failed"); goto error; }
}
- n = mDNSPlatformReadTCP(sd, ((char *)info->reply) + info->nread, info->replylen - info->nread);
- if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; }
- info->nread += n;
- if (info->nread == info->replylen)
+
+ if (m->CurrentRecord)
+ LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+ m->CurrentRecord = m->ResourceRecords;
+ while (m->CurrentRecord)
{
- // Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second)
- DNSMessage *msg = info->reply;
- mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
- msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
- msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
- msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
- msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
- uDNS_ReceiveMsg(m, msg, (mDNSu8 *)msg + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
- mDNSPlatformTCPCloseConnection(sd);
- ufree(info->reply);
- ufree(info);
+ AuthRecord *rptr = m->CurrentRecord;
+ m->CurrentRecord = m->CurrentRecord->next;
+ if (mDNSSameOpaque16(rptr->id, msg->h.id))
+ {
+ err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end);
+ if (!err && rptr->uselease && lease)
+ if (rptr->expire - expire >= 0 || rptr->state != regState_UpdatePending)
+ rptr->expire = expire;
+ hndlRecordUpdateReply(m, rptr, err);
+ m->CurrentRecord = mDNSNULL;
+ return;
+ }
}
}
-
- mDNS_Unlock(m);
- return;
-
- error:
- mDNSPlatformTCPCloseConnection(sd);
- if (info->reply) ufree(info->reply);
- ufree(info);
- mDNS_Unlock(m);
- }
-
-mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m)
- {
- mStatus connectionStatus;
- uDNS_QuestionInfo *info = &question->uDNS_info;
- int sd;
- tcpInfo_t *context;
-
- if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; }
-
- context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t));
- if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; }
- ubzero(context, sizeof(tcpInfo_t));
- context->question = question;
- context->m = m;
- info->id = newMessageID(&m->uDNS_info);
-
- connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd);
- if (connectionStatus == mStatus_ConnEstablished) // manually invoke callback if connection completes
- {
- conQueryCallback(sd, context, mDNStrue);
- return;
- }
- if (connectionStatus == mStatus_ConnPending) return; // callback will be automatically invoked when connection completes
- LogMsg("hndlTruncatedAnswer: connection failed");
- uDNS_StopQuery(m, question); //!!!KRS can we really call this here?
+ debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id));
}
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Dynamic Updates
+#pragma mark - Query Routines
#endif
-mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
+mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
{
- DNSMessage msg;
- mDNSu8 *ptr = msg.data;
- mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
- uDNS_GlobalInfo *u = &m->uDNS_info;
- mDNSOpaque16 id;
- uDNS_RegInfo *regInfo = &rr->uDNS_info;
- mStatus err = mStatus_UnknownErr;
+ mDNSu8 *end;
+ LLQOptData llq;
+ mStatus err;
- id = newMessageID(u);
- InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
- rr->uDNS_info.id = id;
-
- // set zone
- ptr = putZone(&msg, ptr, end, ®Info->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
- if (!ptr) goto error;
+ // If this is supposed to be a private question and the server dropped the TCP connection,
+ // we don't want to cancel it with a clear-text UDP packet, and and it's not worth the expense of
+ // setting up a new TLS session just to cancel the outstanding LLQ, so we just let it expire naturally
+ if (lease == 0 && q->AuthInfo && !q->tcp) return;
- if (regInfo->state == regState_UpdatePending)
+ if (q->AuthInfo && !q->tcp)
{
- // delete old RData
- SetNewRData(&rr->resrec, regInfo->OrigRData, regInfo->OrigRDLen);
- if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error; // delete old rdata
-
- // add new RData
- SetNewRData(&rr->resrec, regInfo->InFlightRData, regInfo->InFlightRDLen);
- if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) goto error;
+ //LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ return;
}
- else
+ if ((q->state == LLQ_Refresh && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
{
- if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
- {
- // KnownUnique: Delete any previous value
- ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype);
- if (!ptr) goto error;
- }
-
- else if (rr->resrec.RecordType != kDNSRecordTypeShared)
- {
- ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end);
- if (!ptr) goto error;
- }
-
- ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
- if (!ptr) goto error;
+ LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), kLLQ_DEF_RETRY/60);
+ q->state = LLQ_Retry;
+ q->LastQTime = m->timenow;
+ q->ThisQInterval = kLLQ_DEF_RETRY * mDNSPlatformOneSecond;
+ SetNextQueryTime(m, q);
+ return;
+ //!!!KRS handle this - periodically try to re-establish
}
-
- if (rr->uDNS_info.lease)
- { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
- err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, ®Info->ns, regInfo->port, -1, GetAuthInfoForName(u, rr->resrec.name));
- if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
-
- SetRecordRetry(m, rr, err);
-
- if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred && regInfo->state != regState_UpdatePending)
- regInfo->state = regState_Pending;
+ llq.vers = kLLQ_Vers;
+ llq.llqOp = kLLQOp_Refresh;
+ llq.err = LLQErr_NoError;
+ llq.id = q->id;
+ llq.llqlease = lease;
- return;
+ InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+ end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue);
+ if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; }
-error:
- LogMsg("sendRecordRegistration: Error formatting message");
- if (rr->uDNS_info.state != regState_Unregistered)
- {
- unlinkAR(&u->RecordRegistrations, rr);
- rr->uDNS_info.state = regState_Unregistered;
- }
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- // NOTE: not safe to touch any client structures here
+ err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
+ if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err);
+
+ if (q->state == LLQ_Established) q->ntries = 1;
+ else q->ntries++;
+
+ debugf("sendLLQRefresh ntries %d %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype));
+
+ q->state = LLQ_Refresh;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
}
-mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
+// wrapper for startLLQHandshake, invoked by async op callback
+mDNSexport void startLLQHandshakeCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
{
- AuthRecord *newRR = (AuthRecord*)authPtr;
- const zoneData_t *zoneData = mDNSNULL;
- uDNS_GlobalInfo *u = &m->uDNS_info;
- AuthRecord *ptr;
-
- // make sure record is still in list
- for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
- if (ptr == newRR) break;
- if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; }
+ DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
- // check error/result
- if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
- if (!result) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error; }
- else zoneData = &result->zoneData;
+ // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
+ // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
+ // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
+ q->nta = mDNSNULL;
- if (newRR->uDNS_info.state == regState_Cancelled)
+ // check state first to make sure it is OK to touch question object
+ if (q->state == LLQ_Cancelled)
{
- //!!!KRS we should send a memfree callback here!
- debugf("Registration of %##s type %d cancelled prior to update",
- newRR->resrec.name->c, newRR->resrec.rrtype);
- newRR->uDNS_info.state = regState_Unregistered;
- unlinkAR(&u->RecordRegistrations, newRR);
+ // StopQuery was called while we were getting the zone info
+ debugf("startLLQHandshakeCallback - LLQ Cancelled.");
return;
}
-
- if (result->type != zoneDataResult)
- {
- LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
- goto error;
- }
- if (newRR->resrec.rrclass != zoneData->zoneClass)
+ mDNS_Lock(m);
+
+ if (q->state != LLQ_GetZoneInfo)
{
- LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
- newRR->resrec.rrclass, zoneData->zoneClass);
- goto error;
+ LogMsg("ERROR: startLLQHandshakeCallback - bad state %d", q->state);
+ err = mStatus_UnknownErr;
+ goto exit;
}
-
- // Don't try to do updates to the root name server.
- // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
- // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
- if (zoneData->zoneName.c[0] == 0)
+
+ if (err)
{
- LogMsg("ERROR: Only name server claiming responsibility for \"%##s\" is \"%##s\"!",
- newRR->resrec.name->c, zoneData->zoneName.c);
- err = mStatus_NoSuchNameErr;
- goto error;
+ LogMsg("ERROR: startLLQHandshakeCallback %##s (%s) invoked with error code %ld", q->qname.c, DNSTypeName(q->qtype), err);
+ StartLLQPolling(m, q);
+ err = mStatus_NoError;
+ goto exit;
}
- // cache zone data
- AssignDomainName(&newRR->uDNS_info.zone, &zoneData->zoneName);
- newRR->uDNS_info.ns = zoneData->primaryAddr;
- if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort;
- else
+ if (!zoneInfo)
{
- debugf("Update port not advertised via SRV - guessing port 53, no lease option");
- newRR->uDNS_info.port = UnicastDNSPort;
- newRR->uDNS_info.lease = mDNSfalse;
+ LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code");
+ err = mStatus_UnknownErr;
+ goto exit;
}
- sendRecordRegistration(m, newRR);
- return;
-
-error:
- if (newRR->uDNS_info.state != regState_Unregistered)
+ if (mDNSIPPortIsZero(zoneInfo->Port))
{
- unlinkAR(&u->RecordRegistrations, newRR);
- newRR->uDNS_info.state = regState_Unregistered;
+ LogOperation("LLQ port lookup failed - reverting to polling for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->servPort = zeroIPPort;
+ StartLLQPolling(m, q);
+ goto exit;
}
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- if (newRR->RecordCallback)
- newRR->RecordCallback(m, newRR, err);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- // NOTE: not safe to touch any client structures here
+
+ // cache necessary zone data
+ q->servAddr = zoneInfo->Addr;
+ q->servPort = zoneInfo->Port;
+ if (!zoneInfo->ZonePrivate) q->AuthInfo = mDNSNULL;
+
+ q->ntries = 0;
+
+ if (q->state == LLQ_SuspendDeferred) q->state = LLQ_Suspended;
+ else startLLQHandshake(m, q);
+
+exit:
+
+ if (err && q) q->state = LLQ_Error;
+
+ mDNS_Unlock(m);
}
-mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
+// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
+mDNSlocal void startPrivateQueryCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
{
- DNSMessage msg;
- mDNSu8 *ptr = msg.data;
- mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
- uDNS_GlobalInfo *u = &m->uDNS_info;
- mDNSOpaque16 id;
- uDNS_RegInfo *rInfo = &srs->uDNS_info;
- mStatus err = mStatus_UnknownErr;
- mDNSIPPort privport;
- NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
- mDNSBool mapped = mDNSfalse;
- domainname target;
- AuthRecord *srv = &srs->RR_SRV;
- mDNSu32 i;
-
- privport = zeroIPPort;
-
- if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; }
+ DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
- id = newMessageID(u);
- InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
+ LogOperation("startPrivateQueryCallback %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- // setup resource records
- SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);
- SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
-
- // replace port w/ NAT mapping if necessary
- if (nat && nat->PublicPort.NotAnInteger &&
- (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy))
+ // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
+ // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
+ // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
+ q->nta = mDNSNULL;
+
+ if (err)
{
- privport = srv->resrec.rdata->u.srv.port;
- srv->resrec.rdata->u.srv.port = nat->PublicPort;
- mapped = mDNStrue;
+ LogMsg("ERROR: startPrivateQueryCallback %##s (%s) invoked with error code %ld", q->qname.c, DNSTypeName(q->qtype), err);
+ goto exit;
}
-
- // construct update packet
- // set zone
- ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass));
- if (!ptr) goto error;
-
- if (srs->uDNS_info.TestForSelfConflict)
+
+ if (!zoneInfo)
{
- // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
- if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error;
- if (!(ptr = putDeleteRRSet(&msg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) goto error;
+ LogMsg("ERROR: startPrivateQueryCallback invoked with NULL result and no error code");
+ err = mStatus_UnknownErr;
+ goto exit;
}
-
- else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending)
+
+ if (!zoneInfo->ZonePrivate)
{
- // use SRV name for prereq
- ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end);
- if (!ptr) goto error;
+ debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->AuthInfo = mDNSNULL; // Clear AuthInfo so we try again non-private
+ q->ThisQInterval = InitialQuestionInterval;
+ q->LastQTime = m->timenow - q->ThisQInterval;
+ mDNS_Lock(m);
+ SetNextQueryTime(m, q);
+ mDNS_Unlock(m);
+ goto exit;
+ // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
}
-
- //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
- if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error;
- for (i = 0; i < srs->NumSubTypes; i++)
- if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) goto error;
-
- if (rInfo->state == regState_UpdatePending) // we're updating the txt record
+ if (!q->AuthInfo)
{
- AuthRecord *txt = &srs->RR_TXT;
- uDNS_RegInfo *txtInfo = &txt->uDNS_info;
- // delete old RData
- SetNewRData(&txt->resrec, txtInfo->OrigRData, txtInfo->OrigRDLen);
- if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error; // delete old rdata
-
- // add new RData
- SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
- if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
+ LogMsg("ERROR: startPrivateQueryCallback: cannot find credentials for q %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ err = mStatus_UnknownErr;
+ goto exit;
}
- else
- if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
- if (!GetServiceTarget(u, srv, &target))
+ q->TargetQID = mDNS_NewMessageID(m);
+ if (q->tcp)
{
- debugf("Couldn't get target for service %##s", srv->resrec.name->c);
- rInfo->state = regState_NoTarget;
- return;
+ LogOperation("startPrivateQueryCallback: Already have TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ tcpCallback(q->tcp->sock, q->tcp, mDNStrue, mStatus_NoError);
}
+ else q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, q, mDNSNULL, mDNSNULL);
- if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
- {
- AssignDomainName(&srv->resrec.rdata->u.srv.target, &target);
- SetNewRData(&srv->resrec, mDNSNULL, 0);
- }
-
- ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl);
- if (!ptr) goto error;
-
- if (srs->uDNS_info.lease)
- { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
-
- err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name));
- if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err);
-
- if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending)
- rInfo->state = regState_Pending;
-
- SetRecordRetry(m, &srs->RR_SRV, err);
- rInfo->id = id;
- if (mapped) srv->resrec.rdata->u.srv.port = privport;
- return;
+exit:
-error:
- LogMsg("SendServiceRegistration - Error formatting message");
- if (mapped) srv->resrec.rdata->u.srv.port = privport;
- unlinkSRS(m, srs);
- rInfo->state = regState_Unregistered;
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- srs->ServiceCallback(m, srs, err);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- //!!!KRS will mem still be free'd on error?
- // NOTE: not safe to touch any client structures here
+ if (err) mDNS_StopQuery(m, q);
}
-mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
+// uDNS_StopLongLivedQuery happens IN ADDITION to stopQuery
+mDNSexport void uDNS_StopLongLivedQuery(mDNS *const m, DNSQuestion *const question)
{
- ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
- const zoneData_t *zoneData = mDNSNULL;
-
- if (err) goto error;
- if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error"); goto error; }
- else zoneData = &result->zoneData;
-
- if (result->type != zoneDataResult)
- {
- LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type);
- goto error;
- }
+ LogOperation("uDNS_StopLongLivedQuery %##s (%s) state %d", question->qname.c, DNSTypeName(question->qtype), question->state);
- if (srs->uDNS_info.state == regState_Cancelled)
- {
- // client cancelled registration while fetching zone data
- srs->uDNS_info.state = regState_Unregistered;
- unlinkSRS(m, srs);
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- srs->ServiceCallback(m, srs, mStatus_MemFree);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- return;
- }
-
- if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
+ switch (question->state)
{
- LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c);
- goto error;
- }
+ case LLQ_UnInit: LogMsg("ERROR: uDNS_StopLongLivedQuery - state LLQ_UnInit"); return; //!!!KRS should we unlink info<->question here?
- // cache zone data
- AssignDomainName(&srs->uDNS_info.zone, &zoneData->zoneName);
- srs->uDNS_info.ns.type = mDNSAddrType_IPv4;
- srs->uDNS_info.ns = zoneData->primaryAddr;
- if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort;
- else
- {
- debugf("Update port not advertised via SRV - guessing port 53, no lease option");
- srs->uDNS_info.port = UnicastDNSPort;
- srs->uDNS_info.lease = mDNSfalse;
+ case LLQ_GetZoneInfo:
+ case LLQ_SuspendDeferred: question->state = LLQ_Cancelled; return;
+
+ case LLQ_Established:
+ case LLQ_Refresh: sendLLQRefresh(m, question, 0); break;
+
+ default: debugf("uDNS_StopLongLivedQuery - silently discarding LLQ in state %d", question->state); break;
}
- if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && IsPrivateV4Addr(&m->uDNS_info.AdvertisedV4))
- { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
- else SendServiceRegistration(m, srs);
- return;
-
-error:
- unlinkSRS(m, srs);
- srs->uDNS_info.state = regState_Unregistered;
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- srs->ServiceCallback(m, srs, err);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- // NOTE: not safe to touch any client structures here
+ RemoveLLQNatMappings(m, question);
+ CheckForUnreferencedLLQMapping(m);
}
-mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Dynamic Updates
+#endif
+
+// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
+mDNSexport void RecordRegistrationCallback(mDNS *const m, mStatus err, const ZoneData *zoneData)
{
- domainname *target = GetRRDomainNameTarget(&rr->resrec);
- AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
+ AuthRecord *newRR = (AuthRecord*)zoneData->ZoneDataContext;
+ AuthRecord *ptr;
- while (ptr && ptr != rr) ptr = ptr->next;
- if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name->c); return mStatus_AlreadyRegistered; }
-
- if (rr->uDNS_info.state == regState_FetchingZoneData ||
- rr->uDNS_info.state == regState_Pending ||
- rr->uDNS_info.state == regState_Registered)
- {
- LogMsg("Requested double-registration of physical record %##s type %d",
- rr->resrec.name->c, rr->resrec.rrtype);
- return mStatus_AlreadyRegistered;
- }
-
- rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse);
- rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
+ if (m->mDNS_busy != m->mDNS_reentrancy)
+ LogMsg("RecordRegistrationCallback: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
+ newRR->nta = mDNSNULL;
+
+ // make sure record is still in list (!!!)
+ for (ptr = m->ResourceRecords; ptr; ptr = ptr->next) if (ptr == newRR) break;
+ if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; }
- if (!ValidateDomainName(rr->resrec.name))
+ // check error/result
+ if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
+ if (!zoneData) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error; }
+
+ if (newRR->resrec.rrclass != zoneData->ZoneClass)
{
- LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr));
- return mStatus_Invalid;
+ LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
+ newRR->resrec.rrclass, zoneData->ZoneClass);
+ goto error;
}
- // Don't do this until *after* we've set rr->resrec.rdlength
- if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
+ // Don't try to do updates to the root name server.
+ // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some
+ // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that.
+ if (zoneData->ZoneName.c[0] == 0)
{
- LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
- return mStatus_Invalid;
+ LogMsg("RecordRegistrationCallback: Only name server claiming responsibility for \"%##s\" is \"%##s\"!", newRR->resrec.name->c, zoneData->ZoneName.c);
+ err = mStatus_NoSuchNameErr;
+ goto error;
}
- rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
- rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
-
- rr->uDNS_info.state = regState_FetchingZoneData;
- rr->next = m->uDNS_info.RecordRegistrations;
- m->uDNS_info.RecordRegistrations = rr;
- rr->uDNS_info.lease = mDNStrue;
-
- return mStatus_NoError;
- }
-
-mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
- {
- mStatus err = SetupRecordRegistration(m, rr);
- if (err) return err;
- else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
- }
+ // Store discovered zone data
+ AssignDomainName(&newRR->zone, &zoneData->ZoneName);
+ newRR->UpdateServer = zoneData->Addr;
+ newRR->UpdatePort = zoneData->Port;
+ newRR->Private = zoneData->ZonePrivate;
+ debugf("RecordRegistrationCallback: Set newRR->UpdateServer %##s %##s to %#a:%d",
+ newRR->resrec.name->c, zoneData->ZoneName.c, &newRR->UpdateServer, mDNSVal16(newRR->UpdatePort));
-mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- DNSMessage msg;
- mDNSu8 *ptr = msg.data;
- mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
- mStatus err;
-
- InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags);
-
- ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
- if (!ptr) goto error;
- if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
+ if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr))
+ {
+ LogMsg("RecordRegistrationCallback: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c);
+ err = mStatus_NoSuchNameErr;
+ goto error;
+ }
- err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(u, rr->resrec.name));
- if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
- SetRecordRetry(m, rr, err);
- rr->uDNS_info.state = regState_DeregPending;
+ mDNS_Lock(m); // SendRecordRegistration expects to be called with the lock held
+ SendRecordRegistration(m, newRR);
+ mDNS_Unlock(m);
return;
- error:
- LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
- unlinkAR(&u->RecordRegistrations, rr);
- rr->uDNS_info.state = regState_Unregistered;
- }
-
-
-
-mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
- {
- uDNS_GlobalInfo *u = &m->uDNS_info;
- NATTraversalInfo *n = rr->uDNS_info.NATinfo;
-
- switch (rr->uDNS_info.state)
+error:
+ if (newRR->state != regState_Unregistered)
{
- case regState_NATMap:
- // we're in the middle of a NAT traversal operation
- rr->uDNS_info.NATinfo = mDNSNULL;
- if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context");
- else FreeNATInfo(m, n); // cause response to outstanding request to be ignored.
- // Note: normally here we're trying to determine our public address,
- //in which case there is not state to be torn down. For simplicity,
- //we allow other operations to expire.
- rr->uDNS_info.state = regState_Unregistered;
- break;
- case regState_ExtraQueued:
- rr->uDNS_info.state = regState_Unregistered;
- break;
- case regState_FetchingZoneData:
- rr->uDNS_info.state = regState_Cancelled;
- return mStatus_NoError;
- case regState_Refresh:
- case regState_Pending:
- case regState_UpdatePending:
- rr->uDNS_info.state = regState_DeregDeferred;
- LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c);
- return mStatus_NoError;
- case regState_Registered:
- case regState_DeregPending:
- break;
- case regState_DeregDeferred:
- case regState_Cancelled:
- LogMsg("Double deregistration of record %##s type %d",
- rr->resrec.name->c, rr->resrec.rrtype);
- return mStatus_UnknownErr;
- case regState_Unregistered:
- LogMsg("Requested deregistration of unregistered record %##s type %d",
- rr->resrec.name->c, rr->resrec.rrtype);
- return mStatus_UnknownErr;
- case regState_NATError:
- case regState_NoTarget:
- LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError");
- return mStatus_UnknownErr;
+ mDNS_Lock(m);
+ UnlinkAuthRecord(m, newRR);
+ newRR->state = regState_Unregistered;
+ mDNS_Unlock(m);
}
- if (rr->uDNS_info.state == regState_Unregistered)
+ // Don't need to do the mDNS_DropLockBeforeCallback stuff here, because this code is
+ // *already* being invoked in the right callback context, with mDNS_reentrancy correctly incremented.
+ if (newRR->RecordCallback)
+ newRR->RecordCallback(m, newRR, err);
+ // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
+ // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
+ }
+
+mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
+ {
+ mDNSu8 *ptr = m->omsg.data;
+ mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+ mStatus err = mStatus_NoError;
+
+ InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags);
+
+ ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+ if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+ if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; }
+
+ rr->state = regState_DeregPending;
+
+ if (rr->Private)
{
- // unlink and deliver memfree
-
- unlinkAR(&u->RecordRegistrations, rr);
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- return mStatus_NoError;
+ LogOperation("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
+ if (rr->tcp) LogMsg("SendRecordDeregistration: ERROR: Already have TCP connection for %s", ARDisplayString(m, rr));
+ else rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
+ rr->LastAPTime = m->timenow;
+ rr->ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us
+ }
+ else
+ {
+ err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+ if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
+ SetRecordRetry(m, rr, err);
+ CompleteDeregistration(m, rr); // Don't touch rr after this
+ return;
}
- rr->uDNS_info.NATinfo = mDNSNULL;
- if (n) FreeNATInfo(m, n);
-
- SendRecordDeregistration(m, rr);
- return mStatus_NoError;
- }
-
-mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
- {
- mDNSu32 i;
- domainname target;
- uDNS_RegInfo *info = &srs->uDNS_info;
- ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations;
- while (*p && *p != srs) p=&(*p)->next;
- if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
- ubzero(info, sizeof(*info));
- *p = srs;
- srs->next = mDNSNULL;
-
- srs->RR_SRV.resrec.rroriginalttl = kWideAreaTTL;
- srs->RR_TXT.resrec.rroriginalttl = kWideAreaTTL;
- srs->RR_PTR.resrec.rroriginalttl = kWideAreaTTL;
- for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kWideAreaTTL;
-
- info->lease = mDNStrue;
+ err = mStatus_NoError;
+
+exit:
- srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
- if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target))
+ if (err)
{
- // defer registration until we've got a target
- debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
- info->state = regState_NoTarget;
- return mStatus_NoError;
+ LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet");
+ UnlinkAuthRecord(m, rr);
+ rr->state = regState_Unregistered;
}
-
- info->state = regState_FetchingZoneData;
- return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
}
-mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
+mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
{
- uDNS_RegInfo *info = &srs->uDNS_info;
- uDNS_GlobalInfo *u = &m->uDNS_info;
- DNSMessage msg;
- mDNSOpaque16 id;
- mDNSu8 *ptr = msg.data;
- mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
- mStatus err = mStatus_UnknownErr;
- mDNSu32 i;
-
- id = newMessageID(u);
- InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
-
- // put zone
- ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
- if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
-
- if (!(ptr = putDeleteAllRRSets(&msg, ptr, srs->RR_SRV.resrec.name))) goto error; // this deletes SRV, TXT, and Extras
- if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
- for (i = 0; i < srs->NumSubTypes; i++)
- if (!(ptr = putDeletionRecord(&msg, ptr, &srs->SubTypes[i].resrec))) goto error;
-
-
- err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name));
- if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; }
+ switch (rr->state)
+ {
+ case regState_NATMap: LogMsg("regState_NATMap %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+ case regState_ExtraQueued: rr->state = regState_Unregistered; break;
+ case regState_Refresh:
+ case regState_Pending:
+ case regState_UpdatePending:
+ rr->state = regState_DeregDeferred;
+ LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c);
+ return mStatus_NoError;
+ case regState_FetchingZoneData:
+ case regState_Registered: break;
+ case regState_DeregPending: break;
+ case regState_DeregDeferred: LogMsg("regState_DeregDeferred %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+ case regState_Unregistered: LogMsg("regState_Unregistered %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+ case regState_NATError: LogMsg("regState_NATError %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+ case regState_NoTarget: LogMsg("regState_NoTarget %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+ default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
+ }
- SetRecordRetry(m, &srs->RR_SRV, err);
- info->id = id;
- info->state = regState_DeregPending;
-
- return;
-
- error:
- unlinkSRS(m, srs);
- info->state = regState_Unregistered;
+ if (rr->state != regState_Unregistered) SendRecordDeregistration(m, rr);
+ return mStatus_NoError;
}
+// Called with lock held
mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
{
- NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
char *errmsg = "Unknown State";
-
+
+ if (m->mDNS_busy != m->mDNS_reentrancy+1)
+ LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+
// don't re-register with a new target following deregistration
- srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
+ srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
+
+ if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
- if (nat)
+ if (srs->NATinfo.clientContext)
{
- if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
- DeleteNATPortMapping(m, nat, srs);
- nat->reg.ServiceRegistration = mDNSNULL;
- srs->uDNS_info.NATinfo = mDNSNULL;
- FreeNATInfo(m, nat);
+ mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+ srs->NATinfo.clientContext = mDNSNULL;
}
-
- switch (srs->uDNS_info.state)
+
+ switch (srs->state)
{
case regState_Unregistered:
debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
return mStatus_BadReferenceErr;
- case regState_FetchingZoneData:
- // let the async op complete, then terminate
- srs->uDNS_info.state = regState_Cancelled;
- return mStatus_NoError; // deliver memfree upon completion of async op
case regState_Pending:
case regState_Refresh:
case regState_UpdatePending:
// deregister following completion of in-flight operation
- srs->uDNS_info.state = regState_DeregDeferred;
+ srs->state = regState_DeregDeferred;
return mStatus_NoError;
case regState_DeregPending:
case regState_DeregDeferred:
- case regState_Cancelled:
debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
return mStatus_NoError;
- case regState_NATError: // not registered
- case regState_NATMap: // not registered
- case regState_NoTarget: // not registered
+ case regState_NATError: // not registered
+ case regState_NATMap: // not registered
+ case regState_NoTarget: // not registered
unlinkSRS(m, srs);
- srs->uDNS_info.state = regState_Unregistered;
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+ srs->state = regState_Unregistered;
+ mDNS_DropLockBeforeCallback();
srs->ServiceCallback(m, srs, mStatus_MemFree);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+ mDNS_ReclaimLockAfterCallback();
return mStatus_NoError;
+ case regState_FetchingZoneData:
case regState_Registered:
- srs->uDNS_info.state = regState_DeregPending;
+ srs->state = regState_DeregPending;
SendServiceDeregistration(m, srs);
return mStatus_NoError;
case regState_ExtraQueued: // only for record registrations
errmsg = "bad state (regState_ExtraQueued)";
goto error;
+ default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
}
error:
return mStatus_BadReferenceErr;
}
-mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
- {
- mStatus err = mStatus_UnknownErr;
-
- extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name
- extra->r.RecordCallback = mDNSNULL; // don't generate callbacks for extra RRs
-
- if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)
- err = uDNS_RegisterRecord(m, &extra->r);
- else
- {
- err = SetupRecordRegistration(m, &extra->r);
- extra->r.uDNS_info.state = regState_ExtraQueued; // %%% Is it okay to overwrite the previous uDNS_info.state?
- }
-
- if (!err)
- {
- extra->next = sr->Extras;
- sr->Extras = extra;
- }
- return err;
- }
-
mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
{
- uDNS_GlobalInfo *u = &m->uDNS_info;
ServiceRecordSet *parent = mDNSNULL;
AuthRecord *rptr;
- uDNS_RegInfo *info = &rr->uDNS_info;
regState_t *stateptr = mDNSNULL;
-
+
// find the record in registered service list
- for (parent = u->ServiceRegistrations; parent; parent = parent->next)
- if (&parent->RR_TXT == rr) { stateptr = &parent->uDNS_info.state; break; }
+ for (parent = m->ServiceRegistrations; parent; parent = parent->uDNS_next)
+ if (&parent->RR_TXT == rr) { stateptr = &parent->state; break; }
if (!parent)
{
// record not part of a service - check individual record registrations
- for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next)
- if (rptr == rr) { stateptr = &rr->uDNS_info.state; break; }
+ for (rptr = m->ResourceRecords; rptr; rptr = rptr->next)
+ if (rptr == rr) { stateptr = &rr->state; break; }
if (!rptr) goto unreg_error;
}
-
+
switch(*stateptr)
{
case regState_DeregPending:
case regState_DeregDeferred:
- case regState_Cancelled:
case regState_Unregistered:
// not actively registered
goto unreg_error;
-
+
case regState_FetchingZoneData:
case regState_NATMap:
case regState_ExtraQueued:
case regState_NoTarget:
// change rdata directly since it hasn't been sent yet
- if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, rr->resrec.rdata);
+ if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata);
SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
rr->NewRData = mDNSNULL;
return mStatus_NoError;
-
+
case regState_Pending:
case regState_Refresh:
case regState_UpdatePending:
- // registration in-flight. queue rdata and return
- if (info->QueuedRData && info->UpdateRDCallback)
+ // registration in-flight. queue rdata and return
+ if (rr->QueuedRData && rr->UpdateCallback)
// if unsent rdata is already queued, free it before we replace it
- info->UpdateRDCallback(m, rr, info->QueuedRData);
- info->QueuedRData = rr->NewRData;
- info->QueuedRDLen = rr->newrdlength;
+ rr->UpdateCallback(m, rr, rr->QueuedRData);
+ rr->QueuedRData = rr->NewRData;
+ rr->QueuedRDLen = rr->newrdlength;
rr->NewRData = mDNSNULL;
return mStatus_NoError;
-
+
case regState_Registered:
- info->OrigRData = rr->resrec.rdata;
- info->OrigRDLen = rr->resrec.rdlength;
- info->InFlightRData = rr->NewRData;
- info->InFlightRDLen = rr->newrdlength;
+ rr->OrigRData = rr->resrec.rdata;
+ rr->OrigRDLen = rr->resrec.rdlength;
+ rr->InFlightRData = rr->NewRData;
+ rr->InFlightRDLen = rr->newrdlength;
rr->NewRData = mDNSNULL;
*stateptr = regState_UpdatePending;
- if (parent) SendServiceRegistration(m, parent);
- else sendRecordRegistration(m, rr);
+ if (parent) SendServiceRegistration(m, parent);
+ else SendRecordRegistration(m, rr);
return mStatus_NoError;
case regState_NATError:
LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c);
- return mStatus_UnknownErr; // states for service records only
+ return mStatus_UnknownErr; // states for service records only
+
+ default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr, rr->resrec.name->c);
}
unreg_error:
return mStatus_Invalid;
}
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - Periodic Execution Routines
#endif
+// See comments above for DNSRelayTestQuestion
+// If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first
+mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q)
+ {
+ int i;
+ mDNSu8 *p = q->qname.c;
+ if (q->AuthInfo) return(mDNStrue); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP
+ if (q->qtype != kDNSType_PTR) return(mDNStrue); // Don't need a test query for any non-PTR queries
+ for (i=0; i<4; i++) // If qname does not begin with num.num.num.num, can't skip the test query
+ {
+ if (p[0] < 1 || p[0] > 3) return(mDNSfalse);
+ if ( p[1] < '0' || p[1] > '9' ) return(mDNSfalse);
+ if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse);
+ if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse);
+ p += 1 + p[0];
+ }
+ // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and
+ // we can safely do it without needing a test query first, otherwise we need the test query.
+ return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa"));
+ }
-mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
+// The question to be checked is not passed in as an explicit parameter;
+// instead it is implicit that the question to be checked is m->CurrentQuestion.
+mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
{
- NATTraversalInfo *ptr = m->uDNS_info.NATTraversals;
- mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
-
- while (ptr)
+ DNSQuestion *q = m->CurrentQuestion;
+ mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
+ // Don't allow sendtime to be earlier than SuppressStdPort53Queries
+ if (!q->LongLived && m->SuppressStdPort53Queries && sendtime - m->SuppressStdPort53Queries < 0)
+ sendtime = m->SuppressStdPort53Queries;
+ if (m->timenow - sendtime < 0) return;
+
+ if (q->LongLived && q->state != LLQ_Poll)
+ {
+ if (q->state >= LLQ_InitialRequest && q->state <= LLQ_Established)
+ {
+ // sanity check to avoid packet flood bugs
+ if (q->state == LLQ_Established || q->state == LLQ_Refresh) sendLLQRefresh(m, q, q->origLease);
+ else if (q->state == LLQ_InitialRequest ) startLLQHandshake(m, q);
+ else if (q->state == LLQ_SecondaryRequest ) sendChallengeResponse(m, q, mDNSNULL);
+ else if (q->state == LLQ_Retry ) { q->ntries = 0; startLLQHandshake(m, q); }
+ }
+ else
+ {
+ // This should never happen. Any LLQ not in states LLQ_InitialRequest to LLQ_Established should not have have ThisQInterval set.
+ // (uDNS_CheckCurrentQuestion() is only called for DNSQuestions with non-zero ThisQInterval)
+ LogMsg("uDNS_CheckCurrentQuestion: %##s (%s) state %d sendtime %d ThisQInterval %d",
+ q->qname.c, DNSTypeName(q->qtype), q->state, sendtime - m->timenow, q->ThisQInterval);
+ q->LastQTime = m->timenow;
+ q->ThisQInterval *= 2;
+ SetNextQueryTime(m, q);
+ }
+ }
+
+ // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
+ if (!(q->LongLived && q->state != LLQ_Poll))
{
- NATTraversalInfo *cur = ptr;
- ptr = ptr->next;
- if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established) // no refresh necessary for established Add requests
+ if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
{
- if (cur->retry - timenow < 0)
+ mDNSu8 *end = m->omsg.data;
+ mStatus err = mStatus_NoError;
+ DomainAuthInfo *private = mDNSNULL;
+
+ if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
+ {
+ err = constructQueryMsg(&m->omsg, &end, q);
+ private = q->AuthInfo;
+ }
+ else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL) // Make sure at least three seconds has elapsed since last test query
+ {
+ LogOperation("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port));
+ q->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
+ q->qDNSServer->lasttest = m->timenow;
+ InitializeDNSMessage(&m->omsg.h, mDNS_NewMessageID(m), uQueryFlags);
+ end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
+ }
+
+ if (err) LogMsg("Error: uDNS_CheckCurrentQuestion - constructQueryMsg. Skipping question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ else
{
- if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
- else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
+ if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
+ {
+ //LogMsg("uDNS_CheckCurrentQuestion %d %p %##s (%s)", sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
+ if (private)
+ {
+ if (q->nta) LogMsg("uDNS_CheckCurrentQuestion Error: GetZoneData already started for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ else q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, startPrivateQueryCallback, q);
+ q->ThisQInterval = 0; // Suspend this question until GetZoneData completes
+ }
+ else
+ {
+ err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL);
+ m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
+ }
+ }
+
+ if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network
+ else if (!q->LongLived && q->ThisQInterval < MAX_UCAST_POLL_INTERVAL)
+ {
+ q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; // Only increase interval if send succeeded
+ LogOperation("Adjusted ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype));
+ }
+ else if (q->LongLived && q->state == LLQ_Poll)
{
- if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
- else SendNATMsg(cur, m);
+ // Bit of a hack here -- if we dropped the interval down to do the DNS test query, need to put
+ // it back or we'll poll every three seconds. The real solution is that the DNS test query
+ // should be a real query in its own right, which other queries are blocked on, rather than
+ // being shoehorned in here and borrowing another question's q->LastQTime and q->ThisQInterval
+ q->ThisQInterval = LLQ_POLL_INTERVAL;
}
}
- else if (cur->retry - nextevent < 0) nextevent = cur->retry;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ }
+ else
+ {
+ // If we have no server for this query, or the only server is a disabled one, then we deliver
+ // a transient failure indication to the client. This is important for things like iPhone
+ // where we want to return timely feedback to the user when no network is available.
+ // After calling MakeNegativeCacheRecord() we store the resulting record in the
+ // cache so that it will be visible to other clients asking the same question
+
+ CacheRecord *rr;
+ const mDNSu32 slot = HashSlot(&q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ if (cg)
+ for (rr = cg->members; rr; rr=rr->next)
+ if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr);
+
+ if (!q->qDNSServer) LogMsg("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
+
+ MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60);
+ // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
+ q->ThisQInterval = 0;
+ CreateNewCacheEntry(m, slot, cg);
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
}
}
- return nextevent;
}
-mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
+mDNSlocal void CheckNATMappings(mDNS *m)
{
- DNSQuestion *q;
- uDNS_GlobalInfo *u = &m->uDNS_info;
- LLQ_Info *llq;
- mDNSs32 sendtime;
- mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
- DNSMessage msg;
mStatus err = mStatus_NoError;
- mDNSu8 *end;
- uDNS_QuestionInfo *info;
-
- u->CurrentQuery = u->ActiveQueries;
- while (u->CurrentQuery)
+ mDNSBool rfc1918 = mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4);
+ mDNSBool HaveRoutable = !rfc1918 && !mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4);
+ m->NextScheduledNATOp = m->timenow + 0x3FFFFFFF;
+
+ if (HaveRoutable) m->ExternalAddress = m->AdvertisedV4.ip.v4;
+
+ if (m->NATTraversals && rfc1918) // Do we need to open NAT-PMP socket to receive multicast announcements from router?
{
- q = u->CurrentQuery;
- info = &q->uDNS_info;
- llq = info->llq;
-
- if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) &&
- info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
+ if (m->NATMcastRecvskt == mDNSNULL) // If we are behind a NAT and the socket hasn't been opened yet, open it
+ {
+ m->NATMcastRecvskt = mDNSPlatformUDPSocket(m, NATPMPAnnouncementPort);
+ m->NATMcastRecvsk2 = mDNSPlatformUDPSocket(m, NATPMPPort); // For backwards compatibility with older base stations that announce on 5351
+ if (!m->NATMcastRecvskt) LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements");
+ if (!m->NATMcastRecvsk2) LogOperation("CheckNATMappings: Failed to allocate port 5351 UDP multicast socket for NAT-PMP announcements");
+ }
+ }
+ else // else, we don't want to listen for announcements, so close them if they're open
+ {
+ if (m->NATMcastRecvskt) { mDNSPlatformUDPClose(m->NATMcastRecvskt); m->NATMcastRecvskt = mDNSNULL; }
+ if (m->NATMcastRecvsk2) { mDNSPlatformUDPClose(m->NATMcastRecvsk2); m->NATMcastRecvsk2 = mDNSNULL; }
+ }
+
+ if (m->NATTraversals)
+ {
+ if (m->timenow - m->retryGetAddr >= 0)
{
- // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
- while (info->knownAnswers)
+ err = uDNS_SendNATMsg(m, mDNSNULL); // Will also do UPnP discovery for us, if necessary
+ if (!err)
{
- CacheRecord *cr = info->knownAnswers;
- info->knownAnswers = info->knownAnswers->next;
-
- m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
- q->QuestionCallback(m, q, &cr->resrec, mDNSfalse);
- m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
- ufree(cr);
- if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
+ if (m->retryIntervalGetAddr < NATMAP_INIT_RETRY) m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
+ else if (m->retryIntervalGetAddr < NATMAP_MAX_RETRY_INTERVAL / 2) m->retryIntervalGetAddr *= 2;
+ else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL;
}
+ // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet
+ // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet
+ m->retryGetAddr = m->timenow + m->retryIntervalGetAddr;
}
- if (q != u->CurrentQuery) continue;
-
- if (q->LongLived && llq->state != LLQ_Poll)
+ // Even when we didn't send the GetAddr packet, still need to make sure NextScheduledNATOp is set correctly
+ if (m->NextScheduledNATOp - m->retryGetAddr > 0)
+ m->NextScheduledNATOp = m->retryGetAddr;
+ }
+
+ if (m->CurrentNATTraversal) LogMsg("WARNING m->CurrentNATTraversal already in use");
+ m->CurrentNATTraversal = m->NATTraversals;
+
+ while (m->CurrentNATTraversal)
+ {
+ NATTraversalInfo *cur = m->CurrentNATTraversal;
+ m->CurrentNATTraversal = m->CurrentNATTraversal->next;
+
+ if (HaveRoutable) // If not RFC 1918 address, our own address and port are effectively our external address and port
+ {
+ cur->ExpiryTime = 0;
+ cur->NewResult = mStatus_NoError;
+ }
+ else if (cur->Protocol) // Check if it's time to send port mapping packets
{
- if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
+ if (m->timenow - cur->retryPortMap >= 0) // Time to do something with this mapping
{
- if (llq->retry - timenow < 0)
+ if (cur->ExpiryTime && cur->ExpiryTime - m->timenow < 0) // Mapping has expired
+ {
+ cur->ExpiryTime = 0;
+ cur->retryInterval = NATMAP_INIT_RETRY;
+ }
+
+ //LogMsg("uDNS_SendNATMsg");
+ err = uDNS_SendNATMsg(m, cur);
+
+ if (cur->ExpiryTime) // If have active mapping then set next renewal time halfway to expiry
+ NATSetNextRenewalTime(m, cur);
+ else // else no mapping; use exponential backoff sequence
{
- // sanity check to avoid packet flood bugs
- if (!llq->retry)
- LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state);
- else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
- sendLLQRefresh(m, q, llq->origLease);
- else if (llq->state == LLQ_InitialRequest)
- startLLQHandshake(m, llq, mDNSfalse);
- else if (llq->state == LLQ_SecondaryRequest)
- sendChallengeResponse(m, q, mDNSNULL);
- else if (llq->state == LLQ_Retry)
- { llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); }
+ if (cur->retryInterval < NATMAP_INIT_RETRY ) cur->retryInterval = NATMAP_INIT_RETRY;
+ else if (cur->retryInterval < NATMAP_MAX_RETRY_INTERVAL / 2) cur->retryInterval *= 2;
+ else cur->retryInterval = NATMAP_MAX_RETRY_INTERVAL;
+ cur->retryPortMap = m->timenow + cur->retryInterval;
}
- else if (llq->retry - nextevent < 0) nextevent = llq->retry;
}
+
+ if (m->NextScheduledNATOp - cur->retryPortMap > 0)
+ m->NextScheduledNATOp = cur->retryPortMap;
}
- else
+
+ // Notify the client if necessary. We invoke the callback if:
+ // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it
+ // and (2) the client doesn't want a mapping, or the client won't need a mapping, or the client has a successful mapping, or we've tried and failed a couple of times
+ // and (3) we have new data to give the client that's changed since the last callback
+ if (!mDNSIPv4AddressIsZero(m->ExternalAddress) || m->retryIntervalGetAddr > NATMAP_INIT_RETRY * 8)
{
- sendtime = q->LastQTime + q->ThisQInterval;
- if (m->SuppressStdPort53Queries &&
- sendtime - m->SuppressStdPort53Queries < 0) // Don't allow sendtime to be earlier than SuppressStdPort53Queries
- sendtime = m->SuppressStdPort53Queries;
- if (sendtime - timenow < 0)
- {
- DNSServer *server = GetServerForName(&m->uDNS_info, &q->qname);
- if (server)
+ const mDNSIPPort ExternalPort = HaveRoutable ? cur->IntPort :
+ !mDNSIPv4AddressIsZero(m->ExternalAddress) && cur->ExpiryTime ? cur->RequestedPort : zeroIPPort;
+ if (!cur->Protocol || HaveRoutable || cur->ExpiryTime || cur->retryInterval > NATMAP_INIT_RETRY * 8)
+ if (!mDNSSameIPv4Address(cur->ExternalAddress, m->ExternalAddress) ||
+ !mDNSSameIPPort (cur->ExternalPort, ExternalPort) ||
+ cur->Result != cur->NewResult)
{
- if (server->teststate == DNSServer_Untested)
- {
- InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), uQueryFlags);
- end = putQuestion(&msg, msg.data, msg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN);
- }
- else
- err = constructQueryMsg(&msg, &end, q);
- if (err) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q->qname.c);
- else
- {
- if (server->teststate != DNSServer_Failed)
- err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &server->addr, UnicastDNSPort, -1, mDNSNULL);
- m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
- q->LastQTime = timenow;
- if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network
- else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2; // don't increase interval if send failed
- }
+ //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval);
+ if (cur->Protocol && mDNSIPPortIsZero(ExternalPort))
+ LogMsg("Failed to obtain NAT port mapping from router %#a external address %.4a internal port %d",
+ &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort));
+ cur->ExternalAddress = m->ExternalAddress;
+ cur->ExternalPort = ExternalPort;
+ cur->Lifetime = cur->ExpiryTime && !mDNSIPPortIsZero(ExternalPort) ?
+ (cur->ExpiryTime - m->timenow + mDNSPlatformOneSecond/2) / mDNSPlatformOneSecond : 0;
+ cur->Result = cur->NewResult;
+ mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
+ if (cur->clientCallback)
+ cur->clientCallback(m, cur);
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
+ // MUST NOT touch cur after invoking the callback
}
- }
- else if (sendtime - nextevent < 0) nextevent = sendtime;
}
- u->CurrentQuery = u->CurrentQuery->next;
}
- return nextevent;
}
-mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
+mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m)
{
AuthRecord *rr;
- uDNS_RegInfo *rInfo;
- uDNS_GlobalInfo *u = &m->uDNS_info;
- mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
-
- //!!!KRS list should be pre-sorted by expiration
- for (rr = u->RecordRegistrations; rr; rr = rr->next)
+ mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
+
+ for (rr = m->ResourceRecords; rr; rr = rr->next)
{
- rInfo = &rr->uDNS_info;
- if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
+ if (rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending || rr->state == regState_DeregDeferred || rr->state == regState_Refresh)
{
- if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
+ if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0)
{
-#if MDNS_DEBUGMSGS
- char *op = "(unknown operation)";
- if (rInfo->state == regState_Pending) op = "registration";
- else if (rInfo->state == regState_DeregPending) op = "deregistration";
- else if (rInfo->state == regState_Refresh) op = "refresh";
- debugf("Retransmit record %s %##s", op, rr->resrec.name->c);
-#endif
- //LogMsg("Retransmit record %##s", rr->resrec.name->c);
- if (rInfo->state == regState_DeregPending) SendRecordDeregistration(m, rr);
- else sendRecordRegistration(m, rr);
+ if (rr->tcp) { rr->LastAPTime = m->timenow; rr->ThisAPInterval = 0x3FFFFFFF; }
+ else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr);
+ else SendRecordRegistration(m, rr);
}
if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
}
- if (rInfo->lease && rInfo->state == regState_Registered)
- {
- if (rInfo->expire - timenow < 0)
- {
- debugf("refreshing record %##s", rr->resrec.name->c);
- rInfo->state = regState_Refresh;
- sendRecordRegistration(m, rr);
- }
- if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
- }
+ if (rr->uselease && rr->state == regState_Registered)
+ {
+ if (rr->expire - m->timenow < 0)
+ {
+ debugf("refreshing record %##s", rr->resrec.name->c);
+ rr->state = regState_Refresh;
+ SendRecordRegistration(m, rr);
+ }
+ if (rr->expire - nextevent < 0) nextevent = rr->expire;
+ }
}
return nextevent;
}
-mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
+mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m)
{
- ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
- uDNS_RegInfo *rInfo;
- mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
-
+ mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
+
+ if (CurrentServiceRecordSet)
+ LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
+ CurrentServiceRecordSet = m->ServiceRegistrations;
+
// Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
- while (s)
+ while (CurrentServiceRecordSet)
{
- ServiceRecordSet *srs = s;
- // NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at,
- // and then if we tried to do srs = srs->next at the end we'd be referencing a dead object
- s = s->next;
-
- rInfo = &srs->uDNS_info;
- if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh || rInfo->state == regState_UpdatePending)
+ ServiceRecordSet *srs = CurrentServiceRecordSet;
+ CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
+ if (srs->state == regState_Pending || srs->state == regState_DeregPending || srs->state == regState_DeregDeferred || srs->state == regState_Refresh || srs->state == regState_UpdatePending)
{
- if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
+ if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow < 0)
{
-#if MDNS_DEBUGMSGS
- char *op = "unknown";
- if (rInfo->state == regState_Pending) op = "registration";
- else if (rInfo->state == regState_DeregPending) op = "deregistration";
- else if (rInfo->state == regState_Refresh) op = "refresh";
- else if (rInfo->state == regState_UpdatePending) op = "txt record update";
- debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name->c);
-#endif
- if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
- else SendServiceRegistration (m, srs);
+ if (srs->tcp) { srs->RR_SRV.LastAPTime = m->timenow; srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; }
+ else if (srs->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
+ else SendServiceRegistration(m, srs);
}
if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
}
- if (rInfo->lease && rInfo->state == regState_Registered)
- {
- if (rInfo->expire - timenow < 0)
- {
- debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
- rInfo->state = regState_Refresh;
- SendServiceRegistration(m, srs);
- }
- if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
- }
+ if (srs->srs_uselease && srs->state == regState_Registered)
+ {
+ if (srs->expire - m->timenow < 0)
+ {
+ debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
+ srs->state = regState_Refresh;
+ SendServiceRegistration(m, srs);
+ }
+ if (srs->expire - nextevent < 0) nextevent = srs->expire;
+ }
}
return nextevent;
}
mDNSexport void uDNS_Execute(mDNS *const m)
{
- uDNS_GlobalInfo *u = &m->uDNS_info;
- mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);
+ mDNSs32 nexte;
- u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
+ m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
- if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0)
- {
- u->DelaySRVUpdate = mDNSfalse;
- UpdateSRVRecords(m);
- }
-
- nexte = CheckNATMappings(m, timenow);
- if (nexte - u->nextevent < 0) u->nextevent = nexte;
+ if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0)
+ { m->NextSRVUpdate = 0; UpdateSRVRecords(m); }
- if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
- m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
+ CheckNATMappings(m);
- nexte = CheckQueries(m, timenow);
- if (nexte - u->nextevent < 0) u->nextevent = nexte;
+ if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
+ m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
- nexte = CheckRecordRegistrations(m, timenow);
- if (nexte - u->nextevent < 0) u->nextevent = nexte;
+ nexte = CheckRecordRegistrations(m);
+ if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
- nexte = CheckServiceRegistrations(m, timenow);
- if (nexte - u->nextevent < 0) u->nextevent = nexte;
-
+ nexte = CheckServiceRegistrations(m);
+ if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
}
// ***************************************************************************
#pragma mark - Startup, Shutdown, and Sleep
#endif
-// DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false
+// DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false
// following a location change, as the server will reject deletions from a source address different
// from the address on which the LLQ was created.
mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive)
{
DNSQuestion *q;
- LLQ_Info *llq;
- for (q = m->uDNS_info.ActiveQueries; q; q = q->next)
+
+ for (q = m->Questions; q; q = q->next)
{
- llq = q->uDNS_info.llq;
- if (q->LongLived && llq)
+ if (q->LongLived)
{
- if (llq->state == LLQ_GetZoneInfo)
+ if (q->state == LLQ_GetZoneInfo)
{
debugf("Marking %##s suspend-deferred", q->qname.c);
- llq->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info
+ q->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info
}
- else if (llq->state < LLQ_Suspended)
+ else if (q->state < LLQ_Suspended)
{
- if (DeregisterActive && (llq->state == LLQ_Established || llq->state == LLQ_Refresh))
- { debugf("Deleting LLQ %##s", q->qname.c); sendLLQRefresh(m, q, 0); }
+ if (DeregisterActive && (q->state == LLQ_Established || q->state == LLQ_Refresh))
+ {
+ debugf("Deleting LLQ %##s", q->qname.c);
+ sendLLQRefresh(m, q, 0);
+ }
debugf("Marking %##s suspended", q->qname.c);
- llq->state = LLQ_Suspended;
- ubzero(llq->id, 8);
+ q->state = LLQ_Suspended;
+
+ if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
+
+ q->id = zeroOpaque64;
+ }
+ else if (q->state == LLQ_Poll)
+ {
+ debugf("Marking %##s suspended-poll", q->qname.c);
+ q->state = LLQ_SuspendedPoll;
}
- else if (llq->state == LLQ_Poll) { debugf("Marking %##s suspended-poll", q->qname.c); llq->state = LLQ_SuspendedPoll; }
- if (llq->NATMap) llq->NATMap = mDNSfalse; // may not need nat mapping if we restart with new route
+
+ RemoveLLQNatMappings(m, q); // may not need nat mapping if we restart with new route
}
}
CheckForUnreferencedLLQMapping(m);
mDNSlocal void RestartQueries(mDNS *m)
{
- uDNS_GlobalInfo *u = &m->uDNS_info;
- DNSQuestion *q;
- LLQ_Info *llqInfo;
- mDNSs32 timenow = mDNSPlatformTimeNow(m);
-
- u->CurrentQuery = u->ActiveQueries;
- while (u->CurrentQuery)
- {
- q = u->CurrentQuery;
- u->CurrentQuery = u->CurrentQuery->next;
- llqInfo = q->uDNS_info.llq;
- q->uDNS_info.RestartTime = timenow;
- q->uDNS_info.Answered = mDNSfalse;
- if (q->LongLived)
+ if (m->CurrentQuestion)
+ LogMsg("RestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ m->CurrentQuestion = m->Questions;
+ while (m->CurrentQuestion)
+ {
+ DNSQuestion *q = m->CurrentQuestion;
+ m->CurrentQuestion = m->CurrentQuestion->next;
+
+ if (!mDNSOpaque16IsZero(q->TargetQID) && !q->DuplicateOf)
{
- if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; }
- if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait)
+ if (q->LongLived)
{
- llqInfo->ntries = -1;
- llqInfo->deriveRemovesOnResume = mDNStrue;
- startLLQHandshake(m, llqInfo, mDNStrue); // we set defer to true since several events that may generate restarts often arrive in rapid succession, and this cuts unnecessary packets
+ if (q->state == LLQ_Suspended || q->state == LLQ_NatMapWaitUDP)
+ {
+ q->ntries = -1;
+ startLLQHandshake(m, q);
+ }
+ else if (q->state == LLQ_SuspendDeferred)
+ q->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual
+ else if (q->state == LLQ_SuspendedPoll)
+ {
+ // if we were polling, we may have had bad zone data due to firewall, etc. - refetch
+ q->ntries = 0;
+ q->state = LLQ_GetZoneInfo;
+ if (q->nta) CancelGetZoneData(m, q->nta); // Make sure we cancel old one before we start a new one
+ q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, startLLQHandshakeCallback, q);
+ }
}
- else if (llqInfo->state == LLQ_SuspendDeferred)
- llqInfo->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual
- else if (llqInfo->state == LLQ_SuspendedPoll)
+ else
{
- // if we were polling, we may have had bad zone data due to firewall, etc. - refetch
- llqInfo->ntries = 0;
- llqInfo->deriveRemovesOnResume = mDNStrue;
- llqInfo->state = LLQ_GetZoneInfo;
- startGetZoneData(&q->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, llqInfo);
+ q->LastQTime = m->timenow;
+ q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; // trigger poll in 3 seconds (to reduce packet rate when restarts come in rapid succession)
+ SetNextQueryTime(m, q);
}
}
- else { q->LastQTime = timenow; q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; } // trigger poll in 1 second (to reduce packet rate when restarts come in rapid succession)
}
+ m->CurrentQuestion = mDNSNULL;
}
mDNSexport void mDNS_UpdateLLQs(mDNS *m)
{
- uDNS_GlobalInfo *u = &m->uDNS_info;
-
mDNS_Lock(m);
- if (u->LLQNatInfo)
- {
- DeleteNATPortMapping(m, u->LLQNatInfo, mDNSNULL);
- FreeNATInfo(m, u->LLQNatInfo); // routine clears u->LLQNatInfo ptr
- }
SuspendLLQs(m, mDNStrue);
RestartQueries(m);
mDNS_Unlock(m);
// simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
// the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
-// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
+// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
// we just move up the timers.
-
-
mDNSlocal void SleepRecordRegistrations(mDNS *m)
{
- DNSMessage msg;
- AuthRecord *rr = m->uDNS_info.RecordRegistrations;
- mDNSs32 timenow = mDNSPlatformTimeNow(m);
+ AuthRecord *rr = m->ResourceRecords;
while (rr)
{
- if (rr->uDNS_info.state == regState_Registered ||
- rr->uDNS_info.state == regState_Refresh)
+ if (rr->state == regState_Registered ||
+ rr->state == regState_Refresh)
{
- mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
- InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags);
-
+ mDNSu8 *ptr = m->omsg.data, *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+ InitializeDNSMessage(&m->omsg.h, mDNS_NewMessageID(m), UpdateReqFlags);
+
// construct deletion update
- ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+ ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }
- ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
- if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
+ ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec);
+ if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
- mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(&m->uDNS_info, rr->resrec.name));
- rr->uDNS_info.state = regState_Refresh;
- rr->LastAPTime = timenow;
+ mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+ rr->state = regState_Refresh;
+ rr->LastAPTime = m->timenow;
rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
}
rr = rr->next;
mDNSlocal void WakeRecordRegistrations(mDNS *m)
{
- mDNSs32 timenow = mDNSPlatformTimeNow(m);
- AuthRecord *rr = m->uDNS_info.RecordRegistrations;
+ AuthRecord *rr = m->ResourceRecords;
while (rr)
{
- if (rr->uDNS_info.state == regState_Refresh)
+ if (rr->state == regState_Refresh)
{
// trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
- rr->LastAPTime = timenow;
+ rr->LastAPTime = m->timenow;
rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
}
rr = rr->next;
mDNSlocal void SleepServiceRegistrations(mDNS *m)
{
- ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
- while(srs)
+ ServiceRecordSet *srs = m->ServiceRegistrations;
+ while (srs)
{
- uDNS_RegInfo *info = &srs->uDNS_info;
- NATTraversalInfo *nat = info->NATinfo;
-
- if (nat)
+ if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; }
+
+ if (srs->NATinfo.clientContext)
{
- if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
- DeleteNATPortMapping(m, nat, srs);
- nat->reg.ServiceRegistration = mDNSNULL;
- srs->uDNS_info.NATinfo = mDNSNULL;
- FreeNATInfo(m, nat);
+ mDNS_StopNATOperation_internal(m, &srs->NATinfo);
+ srs->NATinfo.clientContext = mDNSNULL;
}
- if (info->state == regState_UpdatePending)
+ if (srs->state == regState_UpdatePending)
{
// act as if the update succeeded, since we're about to delete the name anyway
AuthRecord *txt = &srs->RR_TXT;
- uDNS_RegInfo *txtInfo = &txt->uDNS_info;
- info->state = regState_Registered;
+ srs->state = regState_Registered;
// deallocate old RData
- if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData);
- SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen);
- txtInfo->OrigRData = mDNSNULL;
- txtInfo->InFlightRData = mDNSNULL;
+ if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
+ SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
+ txt->OrigRData = mDNSNULL;
+ txt->InFlightRData = mDNSNULL;
}
- if (info->state == regState_Registered || info->state == regState_Refresh)
+ if (srs->state == regState_Registered || srs->state == regState_Refresh)
{
- mDNSOpaque16 origid = srs->uDNS_info.id;
- info->state = regState_DeregPending; // state expected by SendDereg()
+ mDNSOpaque16 origid = srs->id;
+ srs->state = regState_DeregPending; // state expected by SendDereg()
SendServiceDeregistration(m, srs);
- info->id = origid;
- info->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
+ srs->id = origid;
+ srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
}
- srs = srs->next;
+ srs = srs->uDNS_next;
}
}
mDNSlocal void WakeServiceRegistrations(mDNS *m)
{
- mDNSs32 timenow = mDNSPlatformTimeNow(m);
- ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations;
- while(srs)
+ ServiceRecordSet *srs = m->ServiceRegistrations;
+ while (srs)
{
- if (srs->uDNS_info.state == regState_Refresh)
+ if (srs->state == regState_Refresh)
{
// trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets)
- srs->RR_SRV.LastAPTime = timenow;
+ srs->RR_SRV.LastAPTime = m->timenow;
srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
}
- srs = srs->next;
+ srs = srs->uDNS_next;
+ }
+ }
+
+mDNSexport void mDNS_AddSearchDomain(const domainname *const domain)
+ {
+ SearchListElem **p;
+
+ // Check to see if we already have this domain in our list
+ for (p = &SearchList; *p; p = &(*p)->next)
+ if (SameDomainName(&(*p)->domain, domain))
+ {
+ // If domain is already in list, and marked for deletion, change it to "leave alone"
+ if ((*p)->flag == -1) (*p)->flag = 0;
+ LogOperation("mDNS_AddSearchDomain already in list %##s", domain->c);
+ return;
+ }
+
+ // if domain not in list, add to list, mark as add (1)
+ *p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
+ if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
+ mDNSPlatformMemZero(*p, sizeof(SearchListElem));
+ AssignDomainName(&(*p)->domain, domain);
+ (*p)->flag = 1; // add
+ (*p)->next = mDNSNULL;
+ LogOperation("mDNS_AddSearchDomain created new %##s", domain->c);
+ }
+
+mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+ {
+ (void)m; // unused
+ if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
+ }
+
+mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+ {
+ SearchListElem *slElem = question->QuestionContext;
+ mStatus err;
+
+ if (answer->rrtype != kDNSType_PTR) return;
+ if (answer->RecordType == kDNSRecordTypePacketNegative) return;
+
+ if (AddRecord)
+ {
+ const char *name;
+ ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
+ if (!arElem) { LogMsg("ERROR: malloc"); return; }
+ mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
+ if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
+ else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
+ else if (question == &slElem->AutomaticBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseAutomatic];
+ else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
+ else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
+ else { LogMsg("FoundDomain - unknown question"); mDNSPlatformMemFree(arElem); return; }
+
+ MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name);
+ AppendDNSNameString (&arElem->ar.namestorage, "local");
+ AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
+ err = mDNS_Register(m, &arElem->ar);
+ if (err) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err); mDNSPlatformMemFree(arElem); return; }
+ arElem->next = slElem->AuthRecs;
+ slElem->AuthRecs = arElem;
+ }
+ else
+ {
+ ARListElem **ptr = &slElem->AuthRecs;
+ while (*ptr)
+ {
+ if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, &answer->rdata->u.name))
+ {
+ ARListElem *dereg = *ptr;
+ *ptr = (*ptr)->next;
+ debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
+ err = mDNS_Deregister(m, &dereg->ar);
+ if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
+ // Memory will be freed in the FreeARElemCallback
+ }
+ else
+ ptr = &(*ptr)->next;
+ }
}
}
-mDNSexport void uDNS_Init(mDNS *const m)
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+mDNSexport void udns_validatelists(void *const v)
+ {
+ mDNS *const m = v;
+
+ ServiceRecordSet *s;
+ for (s = m->ServiceRegistrations; s; s=s->uDNS_next)
+ if (s->uDNS_next == (ServiceRecordSet*)~0)
+ LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s, s->uDNS_next);
+
+ NATTraversalInfo *n;
+ for (n = m->NATTraversals; n; n=n->next)
+ if (n->next == (NATTraversalInfo *)~0 || n->clientCallback == (NATTraversalClientCallback)~0)
+ LogMemCorruption("m->NATTraversals: %p is garbage", n);
+
+ DNSServer *d;
+ for (d = m->DNSServers; d; d=d->next)
+ if (d->next == (DNSServer *)~0 || d->teststate > DNSServer_Disabled)
+ LogMemCorruption("m->DNSServers: %p is garbage (%d)", d, d->teststate);
+
+ DomainAuthInfo *info;
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->next == (DomainAuthInfo *)~0 || info->AutoTunnel == (mDNSBool)~0)
+ LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info, info->AutoTunnel);
+
+ HostnameInfo *hi;
+ for (hi = m->Hostnames; hi; hi = hi->next)
+ if (hi->next == (HostnameInfo *)~0 || hi->StatusCallback == (mDNSRecordCallback*)~0)
+ LogMemCorruption("m->Hostnames: %p is garbage", n);
+
+ SearchListElem *ptr;
+ for (ptr = SearchList; ptr; ptr = ptr->next)
+ if (ptr->next == (SearchListElem *)~0 || ptr->AuthRecs == (void*)~0)
+ LogMemCorruption("SearchList: %p is garbage (%X)", ptr, ptr->AuthRecs);
+ }
+#endif
+
+// This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
+// is really a UDS API issue, not something intrinsic to uDNS
+
+mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
{
- mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo));
- m->uDNS_info.nextevent = m->timenow_last + 0x78000000;
+ SearchListElem **p = &SearchList, *ptr;
+ mStatus err;
+
+ // step 1: mark each element for removal (-1)
+ for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1;
+
+ // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer
+ mDNS_Lock(m);
+ m->RegisterSearchDomains = mDNStrue;
+ mDNSPlatformSetDNSConfig(m, mDNSfalse, m->RegisterSearchDomains, mDNSNULL, mDNSNULL, mDNSNULL);
+ mDNS_Unlock(m);
+
+ // delete elems marked for removal, do queries for elems marked add
+ while (*p)
+ {
+ ptr = *p;
+ debugf("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c);
+ if (ptr->flag == -1) // remove
+ {
+ ARListElem *arList = ptr->AuthRecs;
+ ptr->AuthRecs = mDNSNULL;
+ *p = ptr->next;
+
+ mDNS_StopGetDomains(m, &ptr->BrowseQ);
+ mDNS_StopGetDomains(m, &ptr->RegisterQ);
+ mDNS_StopGetDomains(m, &ptr->DefBrowseQ);
+ mDNS_StopGetDomains(m, &ptr->DefRegisterQ);
+ mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ);
+ mDNSPlatformMemFree(ptr);
+
+ // deregister records generated from answers to the query
+ while (arList)
+ {
+ ARListElem *dereg = arList;
+ arList = arList->next;
+ debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
+ err = mDNS_Deregister(m, &dereg->ar);
+ if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
+ // Memory will be freed in the FreeARElemCallback
+ }
+ continue;
+ }
+
+ if (ptr->flag == 1) // add
+ {
+ mStatus err1, err2, err3, err4, err5;
+ err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+ err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+ err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+ err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+ err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+ if (err1 || err2 || err3 || err4 || err5)
+ LogMsg("GetDomains for domain %##s returned error(s):\n"
+ "%d (mDNS_DomainTypeBrowse)\n"
+ "%d (mDNS_DomainTypeBrowseDefault)\n"
+ "%d (mDNS_DomainTypeRegistration)\n"
+ "%d (mDNS_DomainTypeRegistrationDefault)"
+ "%d (mDNS_DomainTypeBrowseAutomatic)\n",
+ ptr->domain.c, err1, err2, err3, err4, err5);
+ ptr->flag = 0;
+ }
+
+ if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
+
+ p = &ptr->next;
+ }
+
+ return mStatus_NoError;
}
+// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
+// 1) query for b._dns-sd._udp.local on LocalOnly interface
+// (.local manually generated via explicit callback)
+// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
+// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
+// 4) result above should generate a callback from question in (1). result added to global list
+// 5) global list delivered to client via GetSearchDomainList()
+// 6) client calls to enumerate domains now go over LocalOnly interface
+// (!!!KRS may add outgoing interface in addition)
+
mDNSexport void uDNS_Sleep(mDNS *const m)
{
SuspendLLQs(m, mDNStrue);
WakeServiceRegistrations(m);
WakeRecordRegistrations(m);
}
+
+struct CompileTimeAssertionChecks_uDNS
+ {
+ // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
+ // other overly-large structures instead of having a pointer to them, can inadvertently
+ // cause structure sizes (and therefore memory usage) to balloon unreasonably.
+ char sizecheck_tcpInfo_t [(sizeof(tcpInfo_t) <= 9100) ? 1 : -1];
+ char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 3800) ? 1 : -1];
+ };
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: uDNS.h,v $
-Revision 1.32 2005/07/29 19:46:10 ksekar
-<rdar://problem/4191860> reduce polling period on failed LLQs to 15 minutes
+Revision 1.79 2007/09/20 01:13:19 cheshire
+Export CacheGroupForName so it's callable from other files
+
+Revision 1.78 2007/09/14 21:26:09 cheshire
+<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
+
+Revision 1.77 2007/09/12 23:03:08 cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
+
+Revision 1.76 2007/09/12 19:22:19 cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
+
+Revision 1.75 2007/08/28 23:53:21 cheshire
+Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
+
+Revision 1.74 2007/08/24 00:15:20 cheshire
+Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
+
+Revision 1.73 2007/08/01 03:09:22 cheshire
+<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
+
+Revision 1.72 2007/08/01 00:04:13 cheshire
+<rdar://problem/5261696> Crash in tcpKQSocketCallback
+Half-open TCP connections were not being cancelled properly
+
+Revision 1.71 2007/07/30 23:31:26 cheshire
+Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
+
+Revision 1.70 2007/07/27 20:52:29 cheshire
+Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
+
+Revision 1.69 2007/07/27 19:30:40 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
+
+Revision 1.68 2007/07/27 18:38:56 cheshire
+Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
+
+Revision 1.67 2007/07/20 23:11:12 cheshire
+Fix code layout
-Revision 1.31 2005/03/31 02:19:56 cheshire
-<rdar://problem/4021486> Fix build warnings
-Reviewed by: Scott Herscher
+Revision 1.66 2007/07/16 23:54:48 cheshire
+<rdar://problem/5338850> Crash when removing or changing DNS keys
-Revision 1.30 2005/03/04 03:00:03 ksekar
-<rdar://problem/4026546> Retransmissions happen too early, causing registrations to conflict with themselves
+Revision 1.65 2007/07/16 20:14:22 vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Revision 1.29 2005/01/11 22:50:53 ksekar
-Fixed constant naming (was using kLLQ_DefLease for update leases)
+Revision 1.64 2007/07/11 02:53:36 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add ServiceRecordSet parameter in GetServiceTarget
-Revision 1.28 2004/12/22 00:13:49 ksekar
-<rdar://problem/3873993> Change version, port, and polling interval for LLQ
+Revision 1.63 2007/06/29 00:09:24 vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-Revision 1.27 2004/11/23 04:06:50 cheshire
-Get rid of floating point constant -- in a small embedded device, bringing in all
-the floating point libraries just to halve an integer value is a bit too heavyweight.
+Revision 1.62 2007/05/14 23:53:00 cheshire
+Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
-Revision 1.26 2004/11/22 17:49:15 ksekar
-Changed INIT_REFRESH from fraction to decimal
+Revision 1.61 2007/05/07 20:43:45 cheshire
+<rdar://problem/4241419> Reduce the number of queries and announcements
-Revision 1.25 2004/11/22 17:16:20 ksekar
-<rdar://problem/3854298> Unicast services don't disappear when you disable all networking
+Revision 1.60 2007/05/04 21:46:10 cheshire
+Get rid of uDNS_Close (synonym for uDNS_Sleep)
-Revision 1.24 2004/11/19 04:24:08 ksekar
-<rdar://problem/3682609> Security: Enforce a "window" on one-shot wide-area queries
+Revision 1.59 2007/05/03 22:40:38 cheshire
+<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-Revision 1.23 2004/11/18 18:04:21 ksekar
-Add INIT_REFRESH constant
+Revision 1.58 2007/05/02 22:21:33 cheshire
+<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-Revision 1.22 2004/11/15 20:09:24 ksekar
-<rdar://problem/3719050> Wide Area support for Add/Remove record
+Revision 1.57 2007/04/27 19:28:02 cheshire
+Any code that calls StartGetZoneData needs to keep a handle to the structure, so
+it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
+-- it would start a query and then quickly cancel it, and then when
+StartGetZoneData completed, it had a dangling pointer and crashed.)
-Revision 1.21 2004/11/11 20:14:55 ksekar
-<rdar://problem/3719574> Wide-Area registrations not deregistered on sleep
+Revision 1.56 2007/04/25 02:14:38 cheshire
+<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
+Additional fixes to make LLQs work properly
-Revision 1.20 2004/10/16 00:16:59 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.55 2007/04/22 06:02:03 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.19 2004/09/17 01:08:49 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.54 2007/04/04 21:48:53 cheshire
+<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-Revision 1.18 2004/09/03 19:23:05 ksekar
-<rdar://problem/3788460>: Need retransmission mechanism for wide-area service registrations
+Revision 1.53 2007/03/28 15:56:37 cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-Revision 1.17 2004/09/01 03:59:29 ksekar
-<rdar://problem/3783453>: Conditionally compile out uDNS code on Windows
+Revision 1.52 2007/02/28 01:44:26 cheshire
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-Revision 1.16 2004/08/25 00:37:27 ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
+Revision 1.51 2007/01/27 03:34:27 cheshire
+Made GetZoneData use standard queries (and cached results);
+eliminated GetZoneData_Callback() packet response handler
-Revision 1.15 2004/07/30 17:40:06 ksekar
-<rdar://problem/3739115>: TXT Record updates not available for wide-area services
+Revision 1.50 2007/01/19 21:17:32 cheshire
+StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
-Revision 1.14 2004/07/29 19:27:15 ksekar
-NAT-PMP Support - minor fixes and cleanup
+Revision 1.49 2007/01/17 21:35:31 cheshire
+For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
-Revision 1.13 2004/07/29 02:03:35 ksekar
-Delete unused #define and structure field
+Revision 1.48 2007/01/10 22:51:57 cheshire
+<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-Revision 1.12 2004/07/26 22:49:30 ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.47 2007/01/05 08:30:43 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.11 2004/06/17 01:13:11 ksekar
-<rdar://problem/3696616>: polling interval too short
+Revision 1.46 2007/01/04 01:41:47 cheshire
+Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
-Revision 1.10 2004/06/11 05:45:03 ksekar
-<rdar://problem/3682397>: Change SRV names for LLQ/Update port lookups
+Revision 1.45 2006/12/22 20:59:49 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.9 2004/06/01 23:46:50 ksekar
-<rdar://problem/3675149>: DynDNS: dynamically look up LLQ/Update ports
+Revision 1.44 2006/12/20 04:07:35 cheshire
+Remove uDNS_info substructure from AuthRecord_struct
-Revision 1.8 2004/05/28 23:42:37 ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.43 2006/12/16 01:58:32 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
-Revision 1.7 2004/05/18 23:51:25 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.42 2006/11/30 23:07:56 herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-Revision 1.6 2004/03/13 01:57:33 ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.41 2006/11/18 05:01:30 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
-Revision 1.5 2004/02/21 08:56:58 bradley
-Wrap prototypes with extern "C" for C++ builds.
+Revision 1.40 2006/11/10 07:44:04 herscher
+<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-Revision 1.4 2004/02/06 23:04:19 ksekar
-Basic Dynamic Update support via mDNS_Register (dissabled via
-UNICAST_REGISTRATION #define)
+Revision 1.39 2006/10/20 05:35:05 herscher
+<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-Revision 1.3 2004/01/24 03:38:27 cheshire
-Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport"
+Revision 1.38 2006/09/26 01:54:02 herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-Revision 1.2 2004/01/23 23:23:15 ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.37 2006/09/15 21:20:15 cheshire
+Remove uDNS_info substructure from mDNS_struct
-Revision 1.1 2003/12/13 03:05:27 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.36 2006/08/14 23:24:23 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+Revision 1.35 2006/07/30 05:45:36 cheshire
+<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
+
+Revision 1.34 2006/07/15 02:01:29 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
+
+Revision 1.33 2006/07/05 22:53:28 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
- */
+*/
#ifndef __UDNS_H_
#define __UDNS_H_
#endif
#define RESTART_GOODBYE_DELAY (6 * mDNSPlatformOneSecond) // delay after restarting LLQ before nuking previous known answers (avoids flutter if we restart before we have networking up)
-#define MIN_UCAST_PERIODIC_EXEC (5 * mDNSPlatformOneSecond)
#define INIT_UCAST_POLL_INTERVAL (3 * mDNSPlatformOneSecond) // this interval is used after send failures on network transitions
// which typically heal quickly, so we start agressively and exponentially back off
#define MAX_UCAST_POLL_INTERVAL (60 * 60 * mDNSPlatformOneSecond)
+//#define MAX_UCAST_POLL_INTERVAL (1 * 60 * mDNSPlatformOneSecond)
#define LLQ_POLL_INTERVAL (15 * 60 * mDNSPlatformOneSecond) // Polling interval for zones w/ an advertised LLQ port (ie not static zones) if LLQ fails due to NAT, etc.
#define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond) // require server responses within one minute of request
-#define UPDATE_PORT_NAME "_dns-update._udp."
-#define LLQ_PORT_NAME "_dns-llq._udp"
+
#define DEFAULT_UPDATE_LEASE 7200
-
+
+#define QuestionIntervalStep 3
+#define QuestionIntervalStep2 (QuestionIntervalStep*QuestionIntervalStep)
+#define QuestionIntervalStep3 (QuestionIntervalStep*QuestionIntervalStep*QuestionIntervalStep)
+#define InitialQuestionInterval ((mDNSPlatformOneSecond + QuestionIntervalStep-1) / QuestionIntervalStep)
+
// Entry points into unicast-specific routines
-extern mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
-extern mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u); // returns true if OK to call StopQuery
-extern mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question);
-
-extern void uDNS_Init(mDNS *const m);
+extern void startLLQHandshakeCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
+
+extern void uDNS_StopLongLivedQuery(mDNS *const m, DNSQuestion *const question);
+
extern void uDNS_Sleep(mDNS *const m);
extern void uDNS_Wake(mDNS *const m);
-#define uDNS_Close uDNS_Sleep
-
+
// uDNS_UpdateRecord
// following fields must be set, and the update validated, upon entry.
// rr->NewRData
extern mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra);
extern mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr);
-
-extern mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr);
+
+extern void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q);
+extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name);
+extern mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr);
+// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
+// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
+// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
+typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
+extern mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt);
+extern mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question);
+extern mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question);
+extern mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal);
+
+extern void RecordRegistrationCallback(mDNS *const m, mStatus err, const ZoneData *zoneData);
+extern void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
extern mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr);
-extern mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs);
+extern void ServiceRegistrationZoneDataComplete(mDNS *const m, mStatus err, const ZoneData *result);
+extern const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs);
extern mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs);
+extern void uDNS_CheckCurrentQuestion(mDNS *const m);
+
// integer fields of msg header must be in HOST byte order before calling this routine
extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
- const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr,
- const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
+ const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
-extern void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len);
-
// returns time of next scheduled event
extern void uDNS_Execute(mDNS *const m);
-
+extern mStatus uDNS_SetupDNSConfig(mDNS *const m);
+extern mStatus uDNS_RegisterSearchDomains(mDNS *const m);
+
+typedef enum
+ {
+ uDNS_LLQ_Not = 0, // Normal uDNS answer: Flush any stale records from cache, and respect record TTL
+ uDNS_LLQ_Poll, // LLQ Poll: Flush any stale records from cache, but assume TTL is 2 x poll interval
+ uDNS_LLQ_Setup, // LLQ Initial answer packet: Flush any stale records from cache; assume TTL is 2 x LLQ refresh interval
+ uDNS_LLQ_Events // LLQ event packet: don't flush cache; assume TTL is 2 x LLQ refresh interval
+ } uDNS_LLQType;
+
+extern uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
+extern DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name);
+extern void DisposeTCPConn(struct tcpInfo_t *tcp);
+
+// NAT traversal
+extern void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len); // Called for each received NAT-PMP packet
+extern void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr);
+extern void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease);
+
#ifdef __cplusplus
}
#endif
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: CarbonResource.r,v $
+Revision 1.6 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.5 2003/08/12 19:56:24 cheshire
Update to APSL 2.0
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Mac\040OS\040Test\040Responder.c,v $
+Revision 1.25 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.24 2004/12/16 20:49:34 cheshire
<rdar://problem/3324626> Cache memory management improvements
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Mac\040OS\040Test\040Searcher.c,v $
+Revision 1.23 2007/07/27 19:30:40 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
+
+Revision 1.22 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.21 2004/12/16 20:49:34 cheshire
<rdar://problem/3324626> Cache memory management improvements
// When a new named instance of a service is found, FoundInstance() is called.
// In this sample code we turn around and immediately issue a query to resolve that service name to
// find its address, port, and txtinfo, but a normal browing application would just display the name.
-static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
#pragma unused (question)
SearcherServices *services = (SearcherServices *)question->QuestionContext;
}
}
-static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
#pragma unused (m)
#pragma unused (question)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Responder.c,v $
+Revision 1.3 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/05/20 18:38:31 cheshire
Fix build broken by removal of 'kDNSServiceFlagsAutoRename' from dns_sd.h
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Searcher.c,v $
+Revision 1.4 2006/12/19 22:43:54 cheshire
+Fix compiler warnings
+
+Revision 1.3 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/05/27 06:30:21 cheshire
Add code to test DNSServiceQueryRecord()
static void FoundInstanceInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t notAnIntPort,
- uint16_t txtLen, const char *txtRecord, void *context)
+ uint16_t txtLen, const unsigned char *txtRecord, void *context)
{
linkedServiceInfo *info = (linkedServiceInfo *)context;
SearcherServices *services = info->services;
if (txtLen == 0) info->text[0] = 0;
else
{
- strncpy(info->text, txtRecord+1, txtRecord[0]);
+ strncpy(info->text, (char *)txtRecord+1, txtRecord[0]);
info->text[txtRecord[0]] = 0;
}
info->notAnIntPort.NotAnInteger = notAnIntPort;
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: SubTypeTester.c,v $
+Revision 1.7 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.6 2004/12/16 20:49:35 cheshire
<rdar://problem/3324626> Cache memory management improvements
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSLibrary.c,v $
+Revision 1.4 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2004/12/16 20:49:35 cheshire
<rdar://problem/3324626> Cache memory management improvements
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSLibraryLoader.c,v $
+Revision 1.2 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/03/12 21:30:26 cheshire
Build a System-Context Shared Library from mDNSCore, for the benefit of developers
like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSLibraryResources.r,v $
+Revision 1.54 2007/06/27 21:59:08 cheshire
+mDNSResponder-130
+
+Revision 1.53 2007/05/29 23:47:57 cheshire
+mDNSResponder-129
+
+Revision 1.52 2007/05/25 23:45:39 jvidrine
+Update version numbers to reflect the submission number. (Thanks, Marc!)
+
+Revision 1.51 2007/05/25 22:10:19 cheshire
+mDNSResponder-127
+
+Revision 1.50 2007/05/23 00:57:23 cheshire
+mDNSResponder-126
+
+Revision 1.49 2007/05/15 00:47:50 cheshire
+mDNSResponder-125
+
+Revision 1.48 2007/05/14 20:49:54 cheshire
+mDNSResponder-124
+
+Revision 1.47 2007/05/10 21:43:12 cheshire
+mDNSResponder-123
+
+Revision 1.46 2007/04/27 19:33:07 cheshire
+mDNSResponder-122
+
+Revision 1.45 2007/04/08 03:04:00 cheshire
+mDNSResponder-121
+
+Revision 1.44 2007/03/30 23:30:04 cheshire
+mDNSResponder-120
+
+Revision 1.43 2007/02/28 22:09:24 cheshire
+mDNSResponder-119
+
+Revision 1.42 2007/01/09 01:58:20 cheshire
+mDNSResponder-116
+
+Revision 1.41 2006/11/08 04:29:02 cheshire
+mDNSResponder-115
+
+Revision 1.40 2006/10/27 01:46:40 cheshire
+mDNSResponder-114
+
+Revision 1.39 2006/09/30 01:38:53 cheshire
+mDNSResponder-113
+
+Revision 1.38 2006/09/21 23:38:13 cheshire
+mDNSResponder-112
+
+Revision 1.37 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.36 2006/07/14 00:52:00 cheshire
+mDNSResponder-111
+
+Revision 1.35 2006/06/20 23:05:10 cheshire
+mDNSResponder-110
+
+Revision 1.34 2006/02/09 22:24:53 cheshire
+mDNSResponder-109
+
Revision 1.33 2005/12/12 17:48:36 cheshire
mDNSResponder-108
resource 'vers' (1, purgeable)
{
- 0x01, 0x00, alpha, 108, verUS,
- "1.0a108",
- "Multicast DNS & DNS Service Discovery 1.0a108"
+ 0x01, 0x00, alpha, 130, verUS,
+ "1.0a130",
+ "Multicast DNS & DNS Service Discovery 1.0a130"
};
resource 'vers' (2, purgeable)
{
- 0x01, 0x00, alpha, 108, verUS,
- "1.0a108",
+ 0x01, 0x00, alpha, 130, verUS,
+ "1.0a130",
"developer.apple.com/darwin/projects/bonjour/"
};
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSMacOS9.c,v $
+Revision 1.51 2007/09/12 19:23:17 cheshire
+Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
+
+Revision 1.50 2007/04/05 20:40:37 cheshire
+Remove unused mDNSPlatformTCPGetFlags()
+
+Revision 1.49 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
+
+Revision 1.48 2007/03/20 17:07:15 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
+
+Revision 1.47 2006/12/19 22:43:54 cheshire
+Fix compiler warnings
+
+Revision 1.46 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.45 2006/03/19 02:00:14 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
+
Revision 1.44 2005/09/16 21:06:50 cheshire
Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
#if OTCARBONAPPLICATION
// IP_RCVDSTADDR is known to fail on OS X Carbon, so we'll just assume the packet was probably multicast
- destaddr.ip.v4 = AllDNSLinkGroupv4;
+ destaddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
#endif
if (recvdata.opt.len)
err = OTNextOption(recvdata.opt.buf, recvdata.opt.len, &c);
if (err || !c) break;
if (c->level == INET_IP && c->name == IP_RCVDSTADDR && c->len - kOTOptionHeaderSize == sizeof(destaddr.ip.v4))
- mDNSPlatformMemCopy(c->value, &destaddr.ip.v4, sizeof(destaddr.ip.v4));
+ mDNSPlatformMemCopy(&destaddr.ip.v4, c->value, sizeof(destaddr.ip.v4));
}
}
return(err);
}
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context, int *descriptor)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port)
{
+ (void)m; // Unused
+ (void)flags; // Unused
+ (void)port; // Unused
+ return NULL;
+ }
+
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
+ {
+ (void)flags; // Unused
+ (void)sd; // Unused
+ return NULL;
+ }
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+ {
+ (void)sock; // Unused
+ return -1;
+ }
+
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr * dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+ TCPConnectionCallback callback, void * context)
+ {
+ (void)sock; // Unused
(void)dst; // Unused
(void)dstport; // Unused
(void)InterfaceID; // Unused
(void)callback; // Unused
(void)context; // Unused
- (void)descriptor; // Unused
return(mStatus_UnsupportedErr);
}
-mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sd)
{
(void)sd; // Unused
}
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
{
- (void)sd; // Unused
+ (void)sock; // Unused
(void)buf; // Unused
(void)buflen; // Unused
+ (void)closed; // Unused
return(0);
}
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
{
- (void)sd; // Unused
+ (void)sock; // Unused
(void)msg; // Unused
(void)len; // Unused
return(0);
}
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
+ {
+ (void)m; // Unused
+ (void)port; // Unused
+ return NULL;
+ }
+
+mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
+ {
+ (void)sock; // Unused
+ }
+
mDNSlocal void mDNSOptionManagement(mDNS *const m)
{
OSStatus err;
case mOT_Bind: OTBind(m->p->ep, (TBind*)&mDNSbindReq, NULL); break;
case mOT_Ready: mDNSinitComplete(m, mStatus_NoError);
// Can't do mDNS_RegisterInterface until *after* mDNSinitComplete has set m->mDNSPlatformStatus to mStatus_NoError
- mDNS_RegisterInterface(m, &m->p->interface, 0);
+ mDNS_RegisterInterface(m, &m->p->interface, mDNSfalse);
break;
default: LogMsg("Unexpected m->p->mOTstate %d", m->p->mOTstate-1);
}
if (m->p->mOTstate == mOT_Ready)
{
m->p->mOTstate = mOT_Closed;
- mDNS_DeregisterInterface(m, &m->p->interface);
+ mDNS_DeregisterInterface(m, &m->p->interface, mDNSfalse);
}
if (m->p->ep) { OTCloseProvider(m->p->ep); m->p->ep = NULL; }
break; // Do we need to do anything?
if (m->p->mOTstate == mOT_Ready)
{
m->p->mOTstate = mOT_Closed;
- mDNS_DeregisterInterface(m, &m->p->interface);
+ mDNS_DeregisterInterface(m, &m->p->interface, mDNSfalse);
}
if (m->p->ep) { OTCloseProvider (m->p->ep); m->p->ep = NULL; }
if (m->p->OTTimerTask) { OTDestroyTimerTask(m->p->OTTimerTask); m->p->OTTimerTask = 0; }
else OTLeaveNotifier(m->p->ep);
}
-mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { OTStrCopy((char*)dst, (char*)src); }
-mDNSexport UInt32 mDNSPlatformStrLen (const void *src) { return(OTStrLength((char*)src)); }
-mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, UInt32 len) { OTMemcpy(dst, src, len); }
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, UInt32 len) { return(OTMemcmp(dst, src, len)); }
-mDNSexport void mDNSPlatformMemZero( void *dst, UInt32 len) { OTMemzero(dst, len); }
+mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { OTStrCopy((char*)dst, (char*)src); }
+mDNSexport UInt32 mDNSPlatformStrLen ( const void *src) { return(OTStrLength((char*)src)); }
+mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, UInt32 len) { OTMemcpy(dst, src, len); }
+mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, UInt32 len) { return(OTMemcmp(dst, src, len)); }
+mDNSexport void mDNSPlatformMemZero( void *dst, UInt32 len) { OTMemzero(dst, len); }
mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(OTAllocMem(len)); }
mDNSexport void mDNSPlatformMemFree(void *mem) { OTFreeMem(mem); }
mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) { return(TickCount()); }
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSMacOS9.h,v $
+Revision 1.11 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.10 2004/03/12 21:30:26 cheshire
Build a System-Context Shared Library from mDNSCore, for the benefit of developers
like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSPrefix.h,v $
+Revision 1.4 2006/08/14 23:24:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2004/06/11 00:03:28 cheshire
Add code for testing avail/busy subtypes
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Suppress "warning: 'DNSServiceDiscoveryMachPort' is deprecated" messages -- we already know this code is building the deprecated API
+// Since we compile with all warnings treated as errors, we have to turn off the warnings here or the project won't compile
+#include <AvailabilityMacros.h>
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+
+#include "DNSServiceDiscovery.h"
+#include "DNSServiceDiscoveryDefines.h"
+#include "DNSServiceDiscoveryReplyServer.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <servers/bootstrap.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <pthread.h>
+
+#include <netinet/in.h>
+
+extern boolean_t DNSServiceDiscoveryReply_server(
+ mach_msg_header_t *InHeadP,
+ mach_msg_header_t *OutHeadP);
+
+extern
+kern_return_t DNSServiceBrowserCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString regtype,
+ DNSCString domain
+);
+
+extern
+kern_return_t DNSServiceDomainEnumerationCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ int registrationDomains
+);
+
+extern
+kern_return_t DNSServiceRegistrationCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString name,
+ DNSCString regtype,
+ DNSCString domain,
+ IPPort port,
+ DNSCString txtRecord
+);
+
+extern
+kern_return_t DNSServiceResolverResolve_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString name,
+ DNSCString regtype,
+ DNSCString domain
+);
+
+extern
+kern_return_t DNSServiceRegistrationAddRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ int type,
+ record_data_t data,
+ mach_msg_type_number_t record_dataCnt,
+ uint32_t ttl,
+ natural_t *reference
+);
+
+extern
+int DNSServiceRegistrationUpdateRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ natural_t reference,
+ record_data_t data,
+ mach_msg_type_number_t record_dataCnt,
+ uint32_t ttl
+);
+
+extern
+kern_return_t DNSServiceRegistrationRemoveRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ natural_t reference
+);
+
+struct a_requests {
+ struct a_requests *next;
+ mach_port_t client_port;
+ union {
+ DNSServiceBrowserReply browserCallback;
+ DNSServiceDomainEnumerationReply enumCallback;
+ DNSServiceRegistrationReply regCallback;
+ DNSServiceResolverReply resolveCallback;
+ } callout;
+ void *context;
+};
+
+static struct a_requests *a_requests = NULL;
+static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
+
+typedef struct _dns_service_discovery_t {
+ mach_port_t port;
+} dns_service_discovery_t;
+
+static mach_port_t DNSServiceDiscoveryLookupServer(void)
+{
+ static mach_port_t sndPort = MACH_PORT_NULL;
+ kern_return_t result;
+
+ if (sndPort != MACH_PORT_NULL) {
+ return sndPort;
+ }
+
+ result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort);
+ if (result != KERN_SUCCESS) {
+ printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result);
+ sndPort = MACH_PORT_NULL;
+ }
+
+
+ return sndPort;
+}
+
+static void _increaseQueueLengthOnPort(mach_port_t port)
+{
+ mach_port_limits_t qlimits;
+ kern_return_t result;
+
+ qlimits.mpl_qlimit = 16;
+ result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT);
+
+ if (result != KERN_SUCCESS) {
+ printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result));
+ }
+}
+
+dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.browserCallback = callBack;
+
+ result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating a browser, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+/* Service Enumeration */
+
+dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.enumCallback = callBack;
+
+ result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating an enumerator, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+
+/* Service Registration */
+
+dns_service_discovery_ref DNSServiceRegistrationCreate
+(const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+ IPPort IpPort;
+ char *portptr = (char *)&port;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ if (!txtRecord) {
+ txtRecord = "";
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.regCallback = callBack;
+
+ // older versions of this code passed the port via mach IPC as an int.
+ // we continue to pass it as 4 bytes to maintain binary compatibility,
+ // but now ensure that the network byte order is preserved by using a struct
+ IpPort.bytes[0] = 0;
+ IpPort.bytes[1] = 0;
+ IpPort.bytes[2] = portptr[0];
+ IpPort.bytes[3] = portptr[1];
+
+ result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, IpPort, (char *)txtRecord);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating a resolve, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+/* Resolver requests */
+
+dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.resolveCallback = callBack;
+
+ DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain);
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ natural_t reference = 0;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference);
+
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ }
+
+ return reference;
+}
+
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl);
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ return result;
+ }
+
+ return kDNSServiceDiscoveryNoError;
+}
+
+
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference);
+
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ return result;
+ }
+
+ return kDNSServiceDiscoveryNoError;
+}
+
+void DNSServiceDiscovery_handleReply(void *replyMsg)
+{
+ unsigned long result = 0xFFFFFFFF;
+ mach_msg_header_t * msgSendBufPtr;
+ mach_msg_header_t * receivedMessage;
+ unsigned msgSendBufLength;
+
+ msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize;
+ msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength);
+
+
+ receivedMessage = ( mach_msg_header_t * ) replyMsg;
+
+ // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
+ // genuine mach message. It will then cause the callback to get called.
+ result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr );
+ ( void ) mach_msg_send ( msgSendBufPtr );
+ free(msgSendBufPtr);
+}
+
+mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery)
+{
+ return dnsServiceDiscovery->port;
+}
+
+void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery)
+{
+ struct a_requests *request0, *request;
+ mach_port_t reply = dnsServiceDiscovery->port;
+
+ if (dnsServiceDiscovery->port) {
+ pthread_mutex_lock(&a_requests_lock);
+ request0 = NULL;
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ /* request info found, remove from list */
+ if (request0) {
+ request0->next = request->next;
+ } else {
+ a_requests = request->next;
+ }
+ break;
+ } else {
+ /* not info for this request, skip to next */
+ request0 = request;
+ request = request->next;
+ }
+
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ free(request);
+
+ mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port);
+
+ free(dnsServiceDiscovery);
+ }
+ return;
+}
+
+// reply functions, calls the users setup callbacks with function pointers
+
+kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
+(
+ mach_port_t reply,
+ int resultType,
+ DNSCString replyDomain,
+ int flags
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceDomainEnumerationReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+
+ if (request != NULL) {
+ callback = (*request->callout.enumCallback);
+ requestContext = request->context;
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(resultType, replyDomain, flags, requestContext);
+ }
+
+ return KERN_SUCCESS;
+
+}
+
+kern_return_t internal_DNSServiceBrowserReply_rpc
+(
+ mach_port_t reply,
+ int resultType,
+ DNSCString replyName,
+ DNSCString replyType,
+ DNSCString replyDomain,
+ int flags
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceBrowserReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+ if (request != NULL) {
+ callback = (*request->callout.browserCallback);
+ requestContext = request->context;
+ }
+
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext);
+ }
+
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t internal_DNSServiceRegistrationReply_rpc
+(
+ mach_port_t reply,
+ int resultType
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceRegistrationReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+ if (request != NULL) {
+ callback = (*request->callout.regCallback);
+ requestContext = request->context;
+ }
+
+ pthread_mutex_unlock(&a_requests_lock);
+ if (request != NULL) {
+ (callback)(resultType, requestContext);
+ }
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t internal_DNSServiceResolverReply_rpc
+(
+ mach_port_t reply,
+ sockaddr_t interface,
+ sockaddr_t address,
+ DNSCString txtRecord,
+ int flags
+)
+{
+ struct sockaddr *interface_storage = NULL;
+ struct sockaddr *address_storage = NULL;
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceResolverReply callback = NULL;
+
+ if (interface) {
+ int len = ((struct sockaddr *)interface)->sa_len;
+ interface_storage = (struct sockaddr *)malloc(len);
+ bcopy(interface, interface_storage,len);
+ }
+
+ if (address) {
+ int len = ((struct sockaddr *)address)->sa_len;
+ address_storage = (struct sockaddr *)malloc(len);
+ bcopy(address, address_storage, len);
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+
+ if (request != NULL) {
+ callback = (*request->callout.resolveCallback);
+ requestContext = request->context;
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(interface_storage, address_storage, txtRecord, flags, requestContext);
+ }
+
+ if (interface) {
+ free(interface_storage);
+ }
+ if (address) {
+ free(address_storage);
+ }
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*! @header DNS Service Discovery (Deprecated Mach-based API)
+ *
+ * @discussion This section describes the functions, callbacks, and data structures that
+ * make up the DNS Service Discovery API.
+ *
+ * The DNS Service Discovery API is part of Bonjour, Apple's implementation of
+ * zero-configuration networking (ZEROCONF).
+ *
+ * Bonjour allows you to register a network service, such as a
+ * printer or file server, so that it can be found by name or browsed
+ * for by service type and domain. Using Bonjour, applications can
+ * discover what services are available on the network, along with
+ * all necessary access information-such as name, IP address, and port
+ * number-for a given service.
+ *
+ * In effect, Bonjour combines the functions of a local DNS server
+ * and AppleTalk. Bonjour allows applications to provide user-friendly printer
+ * and server browsing, among other things, over standard IP networks.
+ * This behavior is a result of combining protocols such as multicast and DNS
+ * to add new functionality to the network (such as multicast DNS).
+ *
+ * Bonjour gives applications easy access to services over local IP
+ * networks without requiring the service or the application to support
+ * an AppleTalk or a Netbeui stack, and without requiring a DNS server
+ * for the local network.
+ *
+ * Note that this API was deprecated in Mac OS X 10.3, and replaced
+ * by the portable cross-platform /usr/include/dns_sd.h API.
+ */
+
+#ifndef __DNS_SERVICE_DISCOVERY_H
+#define __DNS_SERVICE_DISCOVERY_H
+
+#include <mach/mach_types.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/cdefs.h>
+
+#include <netinet/in.h>
+
+#include <AvailabilityMacros.h>
+
+__BEGIN_DECLS
+
+/* Opaque internal data type */
+typedef struct _dns_service_discovery_t * dns_service_discovery_ref;
+
+/* possible reply flags values */
+
+enum {
+ kDNSServiceDiscoveryNoFlags = 0,
+ kDNSServiceDiscoveryMoreRepliesImmediately = 1 << 0,
+};
+
+
+/* possible error code values */
+typedef enum
+{
+ kDNSServiceDiscoveryWaiting = 1,
+ kDNSServiceDiscoveryNoError = 0,
+ // mDNS Error codes are in the range
+ // FFFE FF00 (-65792) to FFFE FFFF (-65537)
+ kDNSServiceDiscoveryUnknownErr = -65537, // 0xFFFE FFFF
+ kDNSServiceDiscoveryNoSuchNameErr = -65538,
+ kDNSServiceDiscoveryNoMemoryErr = -65539,
+ kDNSServiceDiscoveryBadParamErr = -65540,
+ kDNSServiceDiscoveryBadReferenceErr = -65541,
+ kDNSServiceDiscoveryBadStateErr = -65542,
+ kDNSServiceDiscoveryBadFlagsErr = -65543,
+ kDNSServiceDiscoveryUnsupportedErr = -65544,
+ kDNSServiceDiscoveryNotInitializedErr = -65545,
+ kDNSServiceDiscoveryNoCache = -65546,
+ kDNSServiceDiscoveryAlreadyRegistered = -65547,
+ kDNSServiceDiscoveryNameConflict = -65548,
+ kDNSServiceDiscoveryInvalid = -65549,
+ kDNSServiceDiscoveryMemFree = -65792 // 0xFFFE FF00
+} DNSServiceRegistrationReplyErrorType;
+
+typedef uint32_t DNSRecordReference;
+
+
+/*!
+@function DNSServiceResolver_handleReply
+ @discussion This function should be called with the Mach message sent
+ to the port returned by the call to DNSServiceResolverResolve.
+ The reply message will be interpreted and will result in a
+ call to the specified callout function.
+ @param replyMsg The Mach message.
+ */
+void DNSServiceDiscovery_handleReply(void *replyMsg);
+
+/* Service Registration */
+
+typedef void (*DNSServiceRegistrationReply) (
+ DNSServiceRegistrationReplyErrorType errorCode,
+ void *context
+);
+
+/*!
+@function DNSServiceRegistrationCreate
+ @discussion Register a named service with DNS Service Discovery
+ @param name The name of this service instance (e.g. "Steve's Printer")
+ @param regtype The service type (e.g. "_printer._tcp." -- see
+ RFC 2782 (DNS SRV) and <http://www.iana.org/assignments/port-numbers>)
+ @param domain The domain in which to register the service (e.g. "apple.com.")
+ @param port The local port on which this service is being offered (in network byte order)
+ @param txtRecord Optional protocol-specific additional information
+ @param callBack The DNSServiceRegistrationReply function to be called
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceRegistrationCreate
+(
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ uint16_t port,
+ const char *txtRecord,
+ DNSServiceRegistrationReply callBack,
+ void *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* DNS Domain Enumeration */
+
+typedef enum
+{
+ DNSServiceDomainEnumerationReplyAddDomain, // Domain found
+ DNSServiceDomainEnumerationReplyAddDomainDefault, // Domain found (and should be selected by default)
+ DNSServiceDomainEnumerationReplyRemoveDomain, // Domain has been removed from network
+} DNSServiceDomainEnumerationReplyResultType;
+
+typedef enum
+{
+ DNSServiceDiscoverReplyFlagsFinished,
+ DNSServiceDiscoverReplyFlagsMoreComing,
+} DNSServiceDiscoveryReplyFlags;
+
+typedef void (*DNSServiceDomainEnumerationReply) (
+ DNSServiceDomainEnumerationReplyResultType resultType, // One of DNSServiceDomainEnumerationReplyResultType
+ const char *replyDomain,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+);
+
+/*!
+ @function DNSServiceDomainEnumerationCreate
+ @discussion Asynchronously create a DNS Domain Enumerator
+ @param registrationDomains A boolean indicating whether you are looking
+ for recommended registration domains
+ (e.g. equivalent to the AppleTalk zone list in the AppleTalk Control Panel)
+ or recommended browsing domains
+ (e.g. equivalent to the AppleTalk zone list in the Chooser).
+ @param callBack The function to be called when domains are found or removed
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceDomainEnumerationCreate
+(
+ int registrationDomains,
+ DNSServiceDomainEnumerationReply callBack,
+ void *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* DNS Service Browser */
+
+typedef enum
+{
+ DNSServiceBrowserReplyAddInstance, // Instance of service found
+ DNSServiceBrowserReplyRemoveInstance // Instance has been removed from network
+} DNSServiceBrowserReplyResultType;
+
+typedef void (*DNSServiceBrowserReply) (
+ DNSServiceBrowserReplyResultType resultType, // One of DNSServiceBrowserReplyResultType
+ const char *replyName,
+ const char *replyType,
+ const char *replyDomain,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+);
+
+/*!
+ @function DNSServiceBrowserCreate
+ @discussion Asynchronously create a DNS Service browser
+ @param regtype The type of service
+ @param domain The domain in which to find the service
+ @param callBack The function to be called when service instances are found or removed
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+*/
+dns_service_discovery_ref DNSServiceBrowserCreate
+(
+ const char *regtype,
+ const char *domain,
+ DNSServiceBrowserReply callBack,
+ void *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Resolver requests */
+
+typedef void (*DNSServiceResolverReply) (
+ struct sockaddr *interface, // Needed for scoped addresses like link-local
+ struct sockaddr *address,
+ const char *txtRecord,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+);
+
+/*!
+@function DNSServiceResolverResolve
+ @discussion Resolved a named instance of a service to its address, port, and
+ (optionally) other demultiplexing information contained in the TXT record.
+ @param name The name of the service instance
+ @param regtype The type of service
+ @param domain The domain in which to find the service
+ @param callBack The DNSServiceResolverReply function to be called when the specified
+ address has been resolved.
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+*/
+
+dns_service_discovery_ref DNSServiceResolverResolve
+(
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ DNSServiceResolverReply callBack,
+ void *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Mach port accessor and deallocation */
+
+/*!
+ @function DNSServiceDiscoveryMachPort
+ @discussion Returns the mach port for a dns_service_discovery_ref
+ @param registration A dns_service_discovery_ref as returned from DNSServiceRegistrationCreate
+ @result A mach reply port which will be sent messages as appropriate.
+ These messages should be passed to the DNSServiceDiscovery_handleReply
+ function. A NULL value indicates that no address was
+ specified or some other error occurred which prevented the
+ resolution from being started.
+*/
+mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+ @function DNSServiceDiscoveryDeallocate
+ @discussion Deallocates the DNS Service Discovery type / closes the connection to the server
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a creation or enumeration call
+ @result void
+*/
+void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Registration updating */
+
+
+/*!
+ @function DNSServiceRegistrationAddRecord
+ @discussion Request that the mDNS Responder add the DNS Record of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param rrtype A standard DNS Resource Record Type, from http://www.iana.org/assignments/dns-parameters
+ @param rdlen Length of the data
+ @param rdata Opaque binary Resource Record data, up to 64 kB.
+ @param ttl time to live for the added record.
+ @result DNSRecordReference An opaque reference that can be passed to the update and remove record calls. If an error occurs, this value will be zero or negative
+*/
+DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+ @function DNSServiceRegistrationUpdateRecord
+ @discussion Request that the mDNS Responder add the DNS Record of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
+ @param rdlen Length of the data
+ @param rdata Opaque binary Resource Record data, up to 64 kB.
+ @param ttl time to live for the updated record.
+ @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
+*/
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+ @function DNSServiceRegistrationRemoveRecord
+ @discussion Request that the mDNS Responder remove the DNS Record(s) of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
+ @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
+*/
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+
+__END_DECLS
+
+#endif /* __DNS_SERVICE_DISCOVERY_H */
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSServiceDiscoveryDefines.h,v $
+Revision 1.8 2006/10/27 00:35:36 cheshire
+DNS_SERVICE_DISCOVERY_SERVER is now com.apple.mDNSResponder, not DNSServiceDiscoveryServer
+
+Revision 1.7 2006/08/14 23:24:39 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.6 2004/09/20 21:45:27 ksekar
Mach IPC cleanup
#include <mach/mach_types.h>
-#define DNS_SERVICE_DISCOVERY_SERVER "DNSServiceDiscoveryServer"
+#define DNS_SERVICE_DISCOVERY_SERVER "com.apple.mDNSResponder"
typedef char DNSCString[1024];
typedef char sockaddr_t[128];
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*/
subsystem
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*/
subsystem
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.dnsextd</string>
+ <key>OnDemand</key>
+ <false/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/dnsextd</string>
+ <string>-launchd</string>
+ </array>
+ <key>ServiceIPC</key>
+ <false/>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.mDNSResponderHelper</string>
+ <key>OnDemand</key>
+ <true/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/mDNSResponderHelper</string>
+ </array>
+ <key>MachServices</key>
+ <dict>
+ <key>com.apple.mDNSResponderHelper</key>
+ <true/>
+ </dict>
+ <key>ServiceIPC</key>
+ <true/>
+</dict>
+</plist>
<string>com.apple.mDNSResponder</string>
<key>OnDemand</key>
<false/>
+ <key>UserName</key>
+ <string>_mdnsresponder</string>
+ <key>GroupName</key>
+ <string>_mdnsresponder</string>
<key>ProgramArguments</key>
<array>
- <string>/usr/sbin/mDNSResponder</string>
- <string>-launchdaemon</string>
+ <string>/usr/sbin/mDNSResponder</string>
+ <string>-launchd</string>
</array>
+ <key>MachServices</key>
+ <dict>
+ <key>com.apple.mDNSResponder</key>
+ <true/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockFamily</key>
+ <string>Unix</string>
+ <key>SockPathName</key>
+ <string>/var/run/mDNSResponder</string>
+ <key>SockPathMode</key>
+ <integer>438</integer>
+ </dict>
+ </dict>
<key>ServiceIPC</key>
- <false/>
+ <true/>
</dict>
</plist>
*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: LegacyNATTraversal.c,v $
-Revision 1.14.2.2 2007/05/09 02:05:49 cheshire
-<rdar://problem/5188970> Change sprintf and strcpy to their safer snprintf and strlcpy equivalents
+Revision 1.40 2007/09/20 21:41:49 cheshire
+<rdar://problem/5495568> Legacy NAT Traversal - unmap request failed with error -65549
+
+Revision 1.39 2007/09/20 20:41:40 cheshire
+Reordered functions in file, in preparation for following fix
+
+Revision 1.38 2007/09/18 21:42:30 cheshire
+To reduce programming mistakes, renamed ExtPort to RequestedPort
+
+Revision 1.37 2007/09/14 21:26:09 cheshire
+<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
+
+Revision 1.36 2007/09/14 01:15:50 cheshire
+Minor fixes for problems discovered in pre-submission testing
+
+Revision 1.35 2007/09/13 00:16:42 cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
+
+Revision 1.34 2007/09/12 23:03:08 cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
+
+Revision 1.33 2007/09/12 19:22:20 cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
+
+Revision 1.32 2007/09/11 19:19:16 cheshire
+Correct capitalization of "uPNP" to "UPnP"
+
+Revision 1.31 2007/09/10 22:14:16 cheshire
+When constructing fake NATAddrReply or NATPortMapReply packet, need to calculate
+plausible upseconds value or core logic will think NAT engine has been rebooted
+
+Revision 1.30 2007/09/05 20:46:17 cheshire
+Tidied up alignment of code layout
+
+Revision 1.29 2007/08/03 20:18:01 vazquez
+<rdar://problem/5382177> LegacyNATTraversal: reading out of bounds can lead to DoS
-Revision 1.14.2.1 2005/12/12 17:38:40 cheshire
-Put buffer overflow bug 4151514 back in by order of Program CCC:
-"Program CCC Denied. This change does not meet the criteria for Chardonnay."
+Revision 1.28 2007/07/31 02:28:36 vazquez
+<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
+
+Revision 1.27 2007/07/30 23:17:03 vazquez
+Since lease times are meaningless in UPnP, return NATMAP_DEFAULT_LEASE in UPnP port mapping reply
+
+Revision 1.26 2007/07/27 22:50:08 vazquez
+Allocate memory for UPnP request and reply buffers instead of using arrays
+
+Revision 1.25 2007/07/27 20:33:44 vazquez
+Make sure we clean up previous port mapping requests before starting an unmap
+
+Revision 1.24 2007/07/27 00:57:48 vazquez
+If a tcp connection is already established for doing a port mapping, don't start it again
+
+Revision 1.23 2007/07/26 21:19:26 vazquez
+Retry port mapping with incremented port number (up to max) in order to handle
+port mapping conflicts on UPnP gateways
+
+Revision 1.22 2007/07/25 21:41:00 vazquez
+Make sure we clean up opened sockets when there are network transitions and when changing
+port mappings
+
+Revision 1.21 2007/07/25 03:05:03 vazquez
+Fixes for:
+<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
+<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
+and a myriad of other security problems
+
+Revision 1.20 2007/07/16 20:15:10 vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
+
+Revision 1.19 2007/06/21 16:37:43 jgraessley
+Bug #: 5280520
+Reviewed by: Stuart Cheshire
+Additional changes to get this compiling on the embedded platform.
+
+Revision 1.18 2007/05/09 01:43:32 cheshire
+<rdar://problem/5187028> Change sprintf and strcpy to their safer snprintf and strlcpy equivalents
+
+Revision 1.17 2007/02/27 02:48:25 cheshire
+Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object
+
+Revision 1.16 2006/08/14 23:24:39 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.15 2006/07/05 23:30:57 cheshire
+Rename LegacyNATInit() -> LNT_Init()
Revision 1.14 2005/12/08 03:00:33 cheshire
<rdar://problem/4349971> Byte order bugs in Legacy NAT traversal code
Revision 1.1 2004/08/18 17:35:41 ksekar
<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
+*/
+#ifdef _LEGACY_NAT_TRAVERSAL_
-*/
+#include "stdlib.h" // For strtol()
+#include "string.h" // For strlcpy(), For strncpy(), strncasecmp()
+#include <arpa/inet.h> // For inet_pton()
#include "mDNSEmbeddedAPI.h"
-#include "mDNSMacOSX.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <sched.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <errno.h>
-
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/sysctl.h>
-#include <net/route.h>
-#include "memory.h"
-#include <ctype.h>
-#include <arpa/inet.h>
-
-//#include "IPAddr.h"
-//#include "upnp.h"
-//#include "debug.h"
-
-// use error codes
-//#include "netaddr.h"
-
-// TODO: remove later and do variable length
-#define MAX_SOAPMSGSIZE 65536
-
-// This code accidentally closes fd 0 all over the place
-// To stop that messing up the mDNSResponder core, we trap it and prevent it
-static int safe_close(int fd)
- {
- if (fd < 3) { /* LogMsg("safe_close: ERROR sd %d < 3", fd); */ return(-1); }
- return(close(fd));
- }
+#include "uDNS.h" // For natTraversalHandleAddressReply() etc.
-#define close safe_close
-
-// This code uses fprintf(stderr, ...) and similar to log error messages
-// We redirect all of them to syslog using our LogMsg mechanism
-#define fprintf(file, ...) LogMsg(__VA_ARGS__)
-
-////////////////////////////////////////////////////////////////////////
-// NetAddr Functions
-////////////////////////////////////////////////////////////////////////
-
-// Return codes
-#define NA_E_SUCCESS (0)
-#define NA_E_INTERNAL_ERROR (-1) /* somewhere something wrong */
-#define NA_E_INVALID_PARAMETER (-2) /* bad params */
-#define NA_E_OPERATION_FAILED (-3) /* can't fulfill request */
-#define NA_E_TIMEOUT (-4) /* operation timed out */
-#define NA_E_THREAD_ERROR (-5) /* some error related to threads */
-#define NA_E_PARSE_ERROR (-6) /* a parsing error occured */
-#define NA_E_NOT_READY (-7) /* this op can't proceed yet */
-#define NA_E_NOT_FOUND (-8) /* resource/prereq not found */
-#define NA_E_NOT_AVAILABLE (-9) /* service not available */
-#define NA_E_EXISTS (-10) /* can't modify existing item */
-#define NA_E_AGAIN (-11) /* something wrong - try again */
-#define NA_E_NOT_SUPPORTED (-12) /* wait until next version */
-#define NA_E_ABORT (-14) /* operation aborted */
-#define NA_E_NET (-15) /* network layer problem */
-
-// Logging flags - log types (increasing degree of detail)
-#define NALOG_ERROR (1UL) /* error messages */
-#define NALOG_ALERT (2UL) /* useful warning/alerts */
-#define NALOG_INFO0 (4UL) /* info - potential problem */
-#define NALOG_INFO1 (8UL) /* extra info */
-#define NALOG_DUMP (16UL) /* data dumps */
-
-#define NALOG_RSRV1 (32UL) /* reserved */
-#define NALOG_RSRV2 (64UL) /* reserved */
-#define NALOG_RSRV3 (128UL) /* reserved */
-
-// Logging flags - component (not used for now)
-#define NALOG_UPNP (256) /* UPnP */
-
-// Default Logging levels
-#define NALOG_LEVEL0 (0)
-#define NALOG_LEVEL1 (NALOG_UPNP | NALOG_ERROR)
-#define NALOG_LEVEL2 (NALOG_LEVEL1 | NALOG_ALERT)
-#define NALOG_LEVEL3 (NALOG_LEVEL2 | NALOG_INFO0)
-#define NALOG_LEVEL4 (NALOG_LEVEL3 | NALOG_INFO1)
-#define NALOG_LEVEL5 (NALOG_LEVEL4 | NALOG_DUMP)
-#define NALOG_DEFAULT_LEVEL (NALOG_LEVEL2)
-
-// Default timeout values (in m-seconds (milli))
-// 50 milliseconds for function timeout
-#define NA_DEFAULT_FUNCTION_TIMEOUT (50)
-
-////////////////////////////////////////////////////////////////////////
-// GLOBAL Defines
-////////////////////////////////////////////////////////////////////////
-#define SSDP_IP "239.255.255.250"
-#define SSDP_PORT 1900
-#define SSDP_TTL 4
-
-#define CRLF "\r\n"
-#define H_CRLF "\r\n"
-// SOAP message's CRLF:
-//#define S_CRLF "\r\n"
-#define S_CRLF
-
-// standard 200 ok msg
-#define HTTP200OK "HTTP/1.1 200 OK\r\n\r\n"
-#define HTTP200OKLEN (sizeof(HTTP200OK) - 1)
-
-// maximum time to wait for an event (in microseconds)
-#define MAX_EXPECTEVENTTIME (10000)
-
-////////////////////////////////////////////////////////////////////////
-// GLOBAL Data Types
-////////////////////////////////////////////////////////////////////////
-typedef struct tagProperty {
- char *pszName;
- char *pszValue;
- char *pszType;
-} Property, *PProperty;
-
-typedef struct tagHTTPResponse {
- char *pszStatus;
- char *pszReason;
- int iNumHeaders;
- Property aHeaders[30]; // assume at most this many headers
- char *pszBody;
-
- // for admin use
- int fFree;
- char *buf;
-} HTTPResponse, *PHTTPResponse, **PPHTTPResponse;
-
-////////////////////////////////////////////////////////////////////////
-// GLOBAL Constants
-////////////////////////////////////////////////////////////////////////
-static const char szSSDPMsgDiscoverRoot[] =
- "M-SEARCH * HTTP/1.1\r\n"
- "Host:239.255.255.250:1900\r\n"
- "ST:upnp:rootdevice\r\n"
- "Man:\"ssdp:discover\"\r\n"
- "MX:3\r\n"
- "\r\n";
-
-static const char szSSDPMsgDiscoverIGD[] =
- "M-SEARCH * HTTP/1.1\r\n"
- "Host:239.255.255.250:1900\r\n"
- "ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n"
- "Man:\"ssdp:discover\"\r\n"
- "MX:3\r\n"
- "\r\n";
-
-static const char szSSDPMsgDiscoverNAT[] =
- "M-SEARCH * HTTP/1.1\r\n"
- "Host:239.255.255.250:1900\r\n"
- "ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n"
- "Man:\"ssdp:discover\"\r\n"
- "MX:3\r\n"
- "\r\n";
-
-//// Subscribe message
-// 1$s: control URL
-// 2$s: local's host/port ("host:port")
-// 3$s: router's host/port ("host:port")
-// 4$d: subscription timeout in seconds
-static const char szEventMsgSubscribeFMT[] =
- "SUBSCRIBE %1$s HTTP/1.1\r\n"
- "NT: upnp:event\r\n"
- "Callback: <http://%2$s/notify>\r\n"
- "Timeout: Second-%4$d\r\n"
- "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
- "Host: %3$s\r\n"
- "Content-Length: 0\r\n"
- "Pragma: no-cache\r\n"
- "\r\n";
-
-//// Unsubscribe message
-// 1$s: control URL
-// 2$s: SID (some uuid passed back during subscribe)
-// 3$s: router's host ("host")
-#if 0
-static const char szEventMsgUnsubscribeFMT[] =
- "UNSUBSCRIBE %1$s HTTP/1.1\r\n"
- "SID: %2$s\r\n"
- "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
- "Host: %3$s\r\n"
- "Content-Length: 0\r\n"
- "Pragma: no-cache\r\n"
- "\r\n";
-#endif
-
-//// Generic SOAP Control:Action request messages
-// 1$s: control URL
-// 2$s: router's host/port ("host:port")
-// 3$s: action (string)
-// 4$d: content-length
-static const char szSOAPMsgControlAHeaderFMT[] =
- //"M-POST %1$s HTTP/1.1\r\n"
- "POST %1$s HTTP/1.1\r\n"
- "Content-Type: text/xml; charset=\"utf-8\"\r\n"
- //"TEST: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
- //"Man: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
- //"01-SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n"
- "SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n"
- "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
- "Host: %2$s\r\n"
- "Content-Length: %4$d\r\n"
- "Connection: close\r\n"
-// "Connection: Keep-Alive\r\n"
- "Pragma: no-cache\r\n"
- "\r\n";
-
-// 1$: action (string)
-// 2$: argument list
-static const char szSOAPMsgControlABodyFMT[] =
- "<?xml version=\"1.0\"?>" CRLF
- "<SOAP-ENV:Envelope" S_CRLF
- " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"" S_CRLF
- " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" S_CRLF
- "<SOAP-ENV:Body>" S_CRLF
- "<m:%1$s" S_CRLF
- " xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" S_CRLF
- "%2$s"
- "</m:%1$s>" S_CRLF
- "</SOAP-ENV:Body>" S_CRLF
- "</SOAP-ENV:Envelope>" S_CRLF
-// CRLF
-// "0"
-// CRLF
- CRLF;
-
-// 1$: argument name
-// 2$: argument value
-static const char szSOAPMsgControlAArgumentFMT[] =
- "<%1$s>%2$s</%1$s>" S_CRLF;
-
-// 1$: argument name
-// 2$: argument value
-// 3$: argument type
-static const char szSOAPMsgControlAArgumentFMT_t[] =
- "<%1$s"
- " xmlns:dt=\"urn:schemas-microsoft-com:datatypes\""
- " dt:dt=\"%3$s\">%2$s</%1$s>" S_CRLF;
-
-#if 0
-//// Generic SOAP Control:Query request messages
-// 1$s: control URL
-// 2$s: router's host/port ("host:port")
-// 3$d: content-length
-static const char szSOAPMsgControlQHeaderFMT[] =
- "M-POST %1$s HTTP/1.1\r\n"
- //"POST %1$s HTTP/1.1\r\n"
- "Host: %2$s\r\n"
- "Content-Length: %3$d\r\n"
- "Content-Type: text/xml; charset-\"utf-8\"\r\n"
- //"Man: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
- //"SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n"
- "01-SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n"
- "\r\n";
-
-// 1$: variable name
-static const char szSOAPMsgControlQBodyFMT[] =
- "<s:Envelope" S_CRLF
- " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" S_CRLF
- " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" S_CRLF
- "<s:Body>" S_CRLF
- "<u:QueryStateVariable xmlns:u=\"urn:schemas-upnp-org:control-1-0\"" S_CRLF
- "<u:varName>%s</u:varName>" S_CRLF
- "</u:QueryStateVariable>" S_CRLF
- "</s:Body>" S_CRLF
- "</s:Envelope>" S_CRLF
- "" S_CRLF;
-#endif
-// 1$: device description URL
-// 2$: host/port
-static const char szSSDPMsgDescribeDeviceFMT[] =
- "GET %s HTTP/1.1\r\n"
- "Accept: text/xml, application/xml\r\n"
- "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
- "Host: %s\r\n"
- "Connection: close\r\n"
-// "Connection: Keep-Alive\r\n"
- "\r\n";
-
-////////////////////////////////////////////////////////////////////////
-// GLOBAL Variables
-////////////////////////////////////////////////////////////////////////
-
-static int g_fFirstInit = TRUE;
-static int g_fQuit = FALSE;
-static FILE *g_log;
-static int g_fLogging;
-
-// Globally-accessible UDP socket
-static int g_sUDP = -1;
-static int g_sUDPCancel = -1;
-
-// Globally-accessible TCP socket
-static int g_sTCP = -1;
-static int g_sTCPCancel = -1;
-
-// Event Vars
-static int g_fEventEnabled = FALSE;
-static unsigned short g_wEventPort;
-static struct sockaddr_in g_saddrRouterEvent;
-static char g_szRouterHostPortEvent[1024];
-static char g_szEventURL[1024];
-
-// UPnP Router info
-static char g_szFriendlyName[1024];
-static char g_szManufacturer[1024];
-static char g_szModelName[1024];
-static char g_szModelDescription[1024];
-
-// URL base
-static struct sockaddr_in g_saddrRouterBase;
-static char g_szRouterHostPortBase[1024];
-
-// the threads
-static pthread_t g_UDPthread = NULL;
-static pthread_t g_TCPthread = NULL;
-
-// Local IP
-static unsigned long g_dwLocalIP = 0;
-
-// Globally accessible info about the router/UPnP
-static int g_fUPnPEnabled = FALSE;
-static char g_szUSN[1024];
-
-static struct sockaddr_in g_saddrRouterDesc;
-static char g_szRouterHostPortDesc[1024];
-static char g_szNATDevDescURL[1024];
-
-static struct sockaddr_in g_saddrRouterSOAP;
-static char g_szRouterHostPortSOAP[1024];
-static char g_szControlURL[1024];
-static int g_fControlURLSet = FALSE;
-
-// Lock/condvar for synchronous upnp calls
-static pthread_mutex_t g_xUPnP;
-static pthread_mutex_t g_xUPnPMsg;
-static pthread_cond_t g_condUPnP;
-static pthread_cond_t g_condUPnPControlURL;
-static struct timeval g_tvUPnPInitTime;
-static struct timeval g_tvLastUpdateTime;
-
-// timeout values in seconds
-static int g_iFunctionTimeout = NA_DEFAULT_FUNCTION_TIMEOUT;
-
-static void GetDeviceDescription(void);
-static void SetLocalIP(void);
-
-////////////////////////////////////////////////////////////////////////
-// IPAddr Functions
-////////////////////////////////////////////////////////////////////////
-
-
-#define ISIPV6 0x01
-#define ISPPP 0x02
-#define IFNAMELEN 16 /* Interface Name Length */
-#define IPLEN 16 /* 16 bytes(128 bits) for IPv6 */
-
-typedef struct tagIPINFO
-{
- int iFlags;
- char szIfName[IFNAMELEN]; /* Interface name */
- unsigned char abIP[IPLEN];
- unsigned short wPort;
-} IPINFO, *PIPINFO, **PPIPINFO;
-
-typedef struct hostent HOSTENT, *PHOSTENT;
-
-static unsigned long GetNATIPNetmask(unsigned long dwIP)
-{
- static const union { uint8_t b[4]; uint32_t l; } mask_10 = { { 255, 0, 0, 0 } }; // Mask for 10/8
- static const union { uint8_t b[4]; uint32_t l; } mask172 = { { 255, 240, 0, 0 } }; // Mask for 172.16/12
- static const union { uint8_t b[4]; uint32_t l; } mask192 = { { 255, 255, 0, 0 } }; // Mask for 192.168/16
- uint8_t *p = (uint8_t *)&dwIP;
- if (p[0] == 10 ) return mask_10.l;
- if (p[0] == 172 && (p[1] & 0xF0) == 16) return mask172.l;
- if (p[0] == 192 && p[1] == 168 ) return mask192.l;
- return 0; /* No NAT IP */
-}
-
-static int GetIPInfo(PPIPINFO ppIPInfo)
-{
- int fd;
- int iLastLen, iLen, iNum = 0, iMax = 0;
- unsigned long dwIP;
- char *pcBuf, *pcTemp;
- PIPINFO pIPInfo = NULL;
- struct ifconf ifc;
- struct ifreq *ifr, ifrcopy;
-
- if (ppIPInfo == NULL) return 0;
-
- fd = socket(AF_INET, SOCK_DGRAM, 0);
-
- iLastLen = -1;
- iLen = 100 * sizeof(struct ifreq);
-
- for (;;)
+// used to format SOAP port mapping arguments
+typedef struct Property_struct
+ {
+ char *name;
+ char *type;
+ char *value;
+ } Property;
+
+// All of the text parsing in this file is intentionally transparent so that we know exactly
+// what's being done to the text, with an eye towards preventing security problems.
+
+// This is an evolving list of useful acronyms to know. Please add to it at will.
+// ST Service Type
+// NT Notification Type
+// USN Unique Service Name
+// UDN Unique Device Name
+// UUID Universally Unique Identifier
+// URN/urn Universal Resource Name
+
+// Forward declaration because of circular reference:
+// SendPortMapRequest -> SendSOAPMsgControlAction -> MakeTCPConnection -> tcpConnectionCallback -> handleLNTPortMappingResponse
+// In the event of a port conflict, handleLNTPortMappingResponse then increments tcpInfo->retries and calls back to SendPortMapRequest to try again
+mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n);
+
+#define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (n)->tcpInfo.retries)
+
+// This function parses the xml body of the device description response from the router. Basically, we look to make sure this is a response
+// referencing a service we care about (WANIPConnection), look for the "controlURL" header immediately following, and copy the addressing and URL info we need
+mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
{
- pcBuf = (char *)malloc(iLen);
- ifc.ifc_len = iLen;
- ifc.ifc_buf = pcBuf;
+ mDNS *m = tcpInfo->m;
+ char *ptr = (char *)tcpInfo->Reply;
+ char *end = (char *)tcpInfo->Reply + tcpInfo->nread;
- if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
+ // find the service we care about
+ while (ptr && ptr != end)
{
- if (errno != EINVAL || iLastLen != -1)
- {
-// DbgPrint(ELL_ERROR, "ioctl failed(%d)\n", errno);
- free(pcBuf);
- close(fd);
- return 0;
- }
+ if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break; // find the first 'W'; is this WANIPConnection? if not, keep looking
+ ptr++;
}
- else
+ if (ptr == mDNSNULL || ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 string"); return; }
+
+ // find "controlURL", starting from where we left off
+ while (ptr && ptr != end)
{
- if (ifc.ifc_len == iLastLen) break;
- iLastLen = ifc.ifc_len;
+ if (*ptr == 'c' && (strncasecmp(ptr, "controlURL", 10) == 0)) break; // find the first 'c'; is this controlURL? if not, keep looking
+ ptr++;
}
+ if (ptr == mDNSNULL || ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
+ ptr += 11; // skip over "controlURL>"
+ if (ptr >= end) { LogOperation("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer
- iLen += 10 * sizeof(struct ifreq);
- free(pcBuf);
- }
-
- for (pcTemp = pcBuf; pcTemp < pcBuf + ifc.ifc_len; )
- {
- if (iNum >= iMax)
+ // is there an address string "http://"? starting from where we left off
+ if (strncasecmp(ptr, "http://", 7) == 0)
{
- PIPINFO pIPInfoNew;
+ int i;
+ char *addrPtr = mDNSNULL;
+
+ ptr += 7; //skip over "http://"
+ if (ptr >= end) { LogOperation("handleLNTDeviceDescriptionResponse: past end of buffer and no URL!"); return; }
+ addrPtr = ptr;
+ for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break; // first find the beginning of the URL and count the chars
+ if (addrPtr == mDNSNULL || addrPtr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find SOAP address string"); return; }
+
+ // allocate the buffer (len i+1 so we have space to terminate the string)
+ if (m->UPnPSOAPAddressString != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPAddressString);
+ if ((m->UPnPSOAPAddressString = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("can't allocate SOAP address string"); return; }
+
+ strncpy((char *)m->UPnPSOAPAddressString, ptr, i); // copy the address string
+ m->UPnPSOAPAddressString[i] = '\0'; // terminate the string
+ }
+
+ if (m->UPnPSOAPAddressString == mDNSNULL) m->UPnPSOAPAddressString = m->UPnPRouterAddressString; // just copy the pointer, don't allocate more memory
+ LogOperation("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);
- iMax += 10;
- pIPInfoNew = (PIPINFO)realloc(pIPInfo, sizeof(IPINFO) * iMax);
- if (pIPInfoNew == NULL)
+ // find port and router URL, starting after the "http://" if it was there
+ while (ptr && ptr != end)
+ {
+ if (*ptr == ':') // found the port number
{
- free(pIPInfo);
- free(pcBuf);
- close(fd);
- return 0;
+ int port;
+ ptr++; // skip over ':'
+ if (ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: reached end of buffer and no address!"); return; }
+ port = (int)strtol(ptr, (char **)mDNSNULL, 10); // get the port
+ m->UPnPSOAPPort = mDNSOpaque16fromIntVal(port); // store it properly converted
}
- else pIPInfo = pIPInfoNew;
-
- memset(pIPInfo + (iMax - 10), 0, sizeof(IPINFO) * 10);
+ else if (*ptr == '/') // found SOAP URL
+ {
+ int j;
+ char *urlPtr = mDNSNULL;
+ if (mDNSIPPortIsZero(m->UPnPSOAPPort)) m->UPnPSOAPPort = m->UPnPRouterPort; // fill in default port if we didn't find one before
+
+ urlPtr = ptr;
+ for (j = 0; urlPtr && urlPtr != end; j++, urlPtr++) if (*urlPtr == '<') break; // first find the next '<' and count the chars
+ if (urlPtr == mDNSNULL || urlPtr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find SOAP URL string"); return; }
+
+ // allocate the buffer (len j+2 because we're copying from the first '/' and so we have space to terminate the string)
+ if (m->UPnPSOAPURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPURL);
+ if ((m->UPnPSOAPURL = (mDNSu8 *)mDNSPlatformMemAllocate(j+1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate SOAP URL"); return; }
+
+ // now copy
+ strncpy((char *)m->UPnPSOAPURL, ptr, j); // this URL looks something like "/uuid:0013-108c-4b3f0000f3dc"
+ m->UPnPSOAPURL[j] = '\0'; // terminate the string
+ break; // we've got everything we need, so get out here
+ }
+ ptr++; // continue
}
- ifr = (struct ifreq *)pcTemp;
-
- pcTemp += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
-
- /* discard invalid address families & loopback */
- if ((ifr->ifr_addr.sa_family != AF_INET &&
- ifr->ifr_addr.sa_family != AF_INET6) ||
- strncmp(ifr->ifr_name, "lo", 2) == 0) continue;
-
- ifrcopy = *ifr;
- ioctl(fd, SIOCGIFFLAGS, &ifrcopy);
- if ((ifrcopy.ifr_flags & IFF_UP) == 0) continue;
-
- switch (ifr->ifr_addr.sa_family)
+ // if we get to the end and haven't found the URL fill in the defaults
+ if (m->UPnPSOAPURL == mDNSNULL)
{
- case AF_INET:
- memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN);
- dwIP = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr;
- memcpy(pIPInfo[iNum].abIP, &dwIP, sizeof(unsigned long));
- if (ifrcopy.ifr_flags & IFF_POINTOPOINT)
- pIPInfo[iNum].iFlags |= ISPPP;
- iNum++;
- break;
-
- case AF_INET6:
- memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN);
- memcpy(pIPInfo[iNum].abIP,
- ((struct sockaddr_in6 *)&(ifr->ifr_addr))-> sin6_addr.s6_addr,
- 16);
- pIPInfo[iNum].iFlags |= ISIPV6;
- if (ifrcopy.ifr_flags & IFF_POINTOPOINT)
- pIPInfo[iNum].iFlags |= ISPPP;
- iNum++;
- break;
-
- default:
- break;
+ m->UPnPSOAPURL = m->UPnPRouterURL; // just copy the pointer, don't allocate more memory
+ m->UPnPSOAPPort = m->UPnPRouterPort;
}
+
+ LogOperation("handleLNTDeviceDescriptionResponse: SOAP URL [%s] port %d", m->UPnPSOAPURL, mDNSVal16(m->UPnPSOAPPort));
}
- free(pcBuf);
- close(fd);
-
- *ppIPInfo = pIPInfo;
-
- return iNum;
-}
-
-static void FreeIPInfo(PIPINFO pIPInfo)
-{
- if (pIPInfo != NULL) free(pIPInfo);
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// Function Definitions
-////////////////////////////////////////////////////////////////////////
-
-static void SendDiscoveryMsg();
-
-// SSDPListen
-// Creates a UDP multicast socket and listens to the SSDP IP/PORT
-// Returns
-// -1 on error, or the socket descriptor if success
-static int SSDPListen()
-{
- char fLoop;
- int iTTL;
- struct ip_mreq mreq;
- struct sockaddr_in saddr;
- int sd;
-
- // IPPROTO_IP == 0; IPPROTO_TCP == 6; IPPROTO_UDP == 17; etc.
- sd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sd == -1) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "Can't create socket! SSDPListen exiting\n");
- return NA_E_NET;
- }
-
- // sock options values
- fLoop = 0; // false - don't send copy to self
- iTTL = SSDP_TTL;
-
- // bind to listen to ssdp multicast address
- bzero(&saddr, sizeof(saddr));
- saddr.sin_len = sizeof(saddr);
- saddr.sin_family = AF_INET;
- //saddr.sin_addr.s_addr = inet_addr(SSDP_IP);
- //saddr.sin_port = htons(SSDP_PORT);
- saddr.sin_addr.s_addr = g_dwLocalIP;
- saddr.sin_port = 0;
-
- // and set the multicast add_member structure
- // (TODO: need to find interfaces later - ioctl, with:
- // SIOCFIFCONF to find if's, SIOCGIFADDR to get addr, and SIOCFIFFLAGS
- // to check for IFF_MULTICAST flag for multicast support on an if)
- bzero(&mreq, sizeof(mreq));
- mreq.imr_interface.s_addr = g_dwLocalIP;
- mreq.imr_multiaddr.s_addr = inet_addr(SSDP_IP);
-
- if (
- bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) //||
- //setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, &fLoop, sizeof(fLoop)) ||
- //setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &iTTL, sizeof(iTTL)) ||
- //setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))
- ) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log,
- "bind/setsockopt for multicast failed... errno = %d\n", errno);
- close(sd);
- return NA_E_NET;
- }
-
- return sd;
-}
-
-static int EventListen()
-{
- struct sockaddr_in saddr;
- int sd;
-
- // try 5 ports before failing completely
- for (g_wEventPort = 5000; g_wEventPort < 5005; g_wEventPort++)
+mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
{
- sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sd == -1) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "Can't create socket! EventListen exiting\n");
- return NA_E_NET;
- }
+ mDNS *m = tcpInfo->m;
+ mDNSu16 err = NATErr_None;
+ mDNSv4Addr ExtAddr;
+ char *addrPtr;
+ char *ptr = (char *)tcpInfo->Reply;
+ char *end = (char *)tcpInfo->Reply + tcpInfo->nread;
- bzero(&saddr, sizeof(saddr));
- saddr.sin_len = sizeof(saddr);
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = g_dwLocalIP;
- saddr.sin_port = htons(g_wEventPort);
+// LogOperation("handleLNTGetExternalAddressResponse: %s", ptr);
- // return if okay
- if (bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0)
+ while (ptr && ptr < end) // Find "NewExternalIPAddress"
{
- listen(sd, 128);
- ////TracePrint(ELL_TRACE, "UPnP: EventListen @%u\n", g_wEventPort);
- return sd;
+ if (*ptr == 'N' && (strncasecmp(ptr, "NewExternalIPAddress", 20) == 0)) break; // find the first 'N'; is this NewExternalIPAddress? if not, keep looking
+ ptr++;
}
+ if (ptr == mDNSNULL || ptr >= end) return; // bad or incomplete response
+ ptr+=21; // skip over "NewExternalIPAddress>"
+ if (ptr >= end) { LogOperation("handleLNTGetExternalAddressResponse: past end of buffer!"); return; }
- // unsuccessful - close sd and try again
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log,
- "bind TCP port %u failed: errno = %d\n", g_wEventPort, errno);
- close(sd);
- }
-
- return NA_E_NET;
-}
+ // find the end of the address and terminate the string so inet_pton() can convert it
+ for (addrPtr = ptr; addrPtr && addrPtr < end; addrPtr++) if (*addrPtr == '<') break; // first find the next '<' and count the chars
+ if (addrPtr == mDNSNULL || addrPtr >= end) { LogOperation("handleLNTGetExternalAddressResponse: didn't find SOAP URL string"); return; }
+ *addrPtr = '\0';
-static void *TCPProc(void *in);
+ if (inet_pton(AF_INET, ptr, &ExtAddr) <= 0)
+ { LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address"); err = NATErr_NetFail; }
+ if (!err) LogOperation("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr);
-static int EventInit()
-{
- int iRet;
- pthread_attr_t attr;
+ natTraversalHandleAddressReply(m, err, ExtAddr);
+ }
- if (g_fEventEnabled == FALSE)
+mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
{
- // initialize TCP socket for Eventing
- g_sTCP = EventListen();
- if (g_sTCP < 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "EventInit - Failed to init tcp socket.\n");
- return NA_E_INTERNAL_ERROR;
- }
+ mDNS *m = tcpInfo->m;
+ mDNSIPPort extport = zeroIPPort;
+ char *ptr = (char *)tcpInfo->Reply;
+ char *end = (char *)tcpInfo->Reply + tcpInfo->nread;
+ NATTraversalInfo *natInfo;
- // make TCP thread
- pthread_attr_init(&attr);
- iRet = pthread_create(&g_TCPthread, &attr, TCPProc, 0);
- if (iRet != 0) {
- close(g_sTCP);
- g_sTCP = -1;
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "EventInit: TCPProc create failed(%d)\n", iRet);
- return NA_E_THREAD_ERROR;
- }
- }
+ for (natInfo = m->NATTraversals; natInfo; natInfo=natInfo->next) { if (natInfo == tcpInfo->parentNATInfo) break; }
+
+ if (!natInfo) { LogOperation("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; }
- g_fEventEnabled = TRUE;
-
- return NA_E_SUCCESS;
-}
-
-static void DumpHex(char *buf, int len)
-{
- int i;
- int nexti;
- int j;
- int endj;
-
- if (g_fLogging & NALOG_DUMP) {
- if (buf == NULL) return;
- if (len <= 0) return;
-
- for (i = 0; i < len; i = nexti) {
- fprintf(g_log, "%04x: ", i);
- nexti = i + 16;
- endj = (nexti > len) ? len : nexti;
- for (j = i; j < endj; j++)
- fprintf(g_log, "%02x %c ", buf[j] & 0xff, buf[j]);
- if (j == len) {
- if ((j % 16) != 0) {
- char pad[3 * 16 + 1]; // don't need the last 3 bytes anyway
- j = (16 - (j % 16)) * 3;
- memset(pad, ' ', j);
- pad[j] = '\0';
- fputs(pad, g_log);
+ // start from the beginning of the HTTP header; find "200 OK" status message; if the first characters after the
+ // space are not "200" then this is an error message or invalid in some other way
+ // if the error is "500" this is an internal server error
+ while (ptr && ptr != end)
+ {
+ if (*ptr == ' ')
+ {
+ ptr++;
+ if (ptr == end) { LogOperation("handleLNTPortMappingResponse: past end of buffer!"); return; }
+ if (strncasecmp(ptr, "200", 3) == 0) break;
+ else if (strncasecmp(ptr, "500", 3) == 0)
+ {
+ // now check to see if this was a port mapping conflict
+ while (ptr && ptr != end)
+ {
+ if ((*ptr == 'c' || *ptr == 'C') && strncasecmp(ptr, "Conflict", 8) == 0)
+ {
+ if (tcpInfo->retries < 100)
+ { tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo); }
+ else
+ {
+ LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort));
+ natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Refused, zeroIPPort, 0);
+ }
+ return;
+ }
+ ptr++;
+ }
+ break; // out of HTTP status search
}
}
- for (j = i; j < endj; j++)
- isprint(buf[j]) ? fputc(buf[j], g_log) : fputc('.', g_log);
- fputc('\n', g_log);
+ ptr++;
}
+ if (ptr == mDNSNULL || ptr == end) return;
+
+ LogOperation("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
+ mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
- }
-}
-
-// FindHTTPHeaderNewLine
-// Returns a pointer to the beginning of a CRLF, that is not a
-// part of LWS. (LWS is CRLF followed by a space or tab, and in
-// HTTP, considered as equivalent to a single space) (LWS stands
-// for "linear white space")
-// Returns a pointer the beginning of CRLF, and sets the EOH flag to
-// whether this is the last header in the HTTP header section.
-// Also, if pbuf is NULL, or if there isn't any CRLF found in the
-// string, or if the HTTP syntax is wrong, NULL is returned, and
-// the EOH flag is not touched.
-static char *FindHTTPHeaderNewLine(char *pbuf, int iBufSize, int *pfEOH)
-{
- char *result;
- int i = 0;
-
- if (pbuf == NULL) return NULL;
-
- for (;;) {
- result = memchr(pbuf, '\r', iBufSize);
- if (result == NULL) {
- if (g_fLogging & NALOG_INFO0) {
- fprintf(g_log, "FindHTTPHeaderNewLine: er @(%d/%d)\n", i, iBufSize);
- fflush(g_log);
- }
- return NULL;
- }
- i++; // count chars
-
- // decrement iBufSize, and move pbuf forward
- iBufSize -= (result - pbuf);
- pbuf = result;
-
- ++pbuf; // now pointing right after "\r"
- --iBufSize;
- if (*pbuf == '\0') break;
- if (*pbuf != '\n') continue;
-
- ++pbuf; // now pointing after "\r\n"
- --iBufSize;
- if (*pbuf == '\0') break;
- if ((*pbuf == ' ') || (*pbuf == '\t')) continue;
-
- // at this point we know we're at the end of a header field,
- // and there's more stuff coming...
-
- // just need to check if this is the last header
- if ((pbuf[0] == '\r') && (pbuf[1] == '\n'))
- *pfEOH = TRUE;
- else
- *pfEOH = FALSE;
-
- return result;
- }
-
- return NULL;
-}
-
-// NewHTTPResponse_sz
-// Creates an HTTPResponse structure from a string (sz). Set
-// fDestroyOriginal to TRUE if the buffer passed in can be overwritten.
-// Otherwise, NewHTTPResponse_sz will duplicate the buffer.
-// Returns the created HTTPResponse structure if successful, or if an
-// error occured (out of memory, or bad http syntax), returns NULL.
-// NOTE: ALWAYS call DeleteHTTPResponse after using the HTTPResponse structure.
-// NOTE: The input is assumed to be correct. If there're HTTP syntax errors,
-// and the pszHTTPResponse is not null-terminated, result may be undefined.
-// (to be fixed next version)
-static PHTTPResponse NewHTTPResponse_sz(
- char *pszHTTPResponse,
- int iBufferSize,
- int fDestroyOriginal)
-{
- PHTTPResponse pResponse;
- int fEOH;
- char *pszEOL;
- int iNumHeaders;
- char *pBuf;
-
- if ((pResponse = (PHTTPResponse)malloc(sizeof(HTTPResponse))) == NULL) {
- if (g_fLogging & NALOG_INFO0) {
- fprintf(g_log, "NewHTTPResponse_sz: er 1\n");
- fflush(g_log);
- }
- return NULL;
- }
-
- // make copy of buffer now
- if (fDestroyOriginal) {
- pResponse->buf = NULL;
- pBuf = pszHTTPResponse;
- }
- else {
- int len = strlen(pszHTTPResponse);
- if ((len+1) > iBufferSize) {
- if (g_fLogging & NALOG_INFO0)
- fprintf(g_log, "Length: %d > %d\n", len+1, iBufferSize);
- iBufferSize = len+1;
- }
- if ((pResponse->buf = (char *)malloc(iBufferSize)) == NULL) {
- free(pResponse);
- if (g_fLogging & NALOG_INFO0) {
- fprintf(g_log, "NewHTTPResponse_sz: er 2\n");
- fflush(g_log);
- }
- return NULL;
- }
- memcpy(pResponse->buf, pszHTTPResponse, iBufferSize);
- pBuf = pResponse->buf;
- }
-
- // get the first line
- pszEOL = FindHTTPHeaderNewLine(pBuf, iBufferSize, &fEOH);
- if (pszEOL == NULL) {
- if (g_fLogging & NALOG_INFO0) {
- fprintf(g_log, "NewHTTPResponse_sz: er 3\n");
- fflush(g_log);
- }
- goto cleanup;
- }
-
- *pszEOL = '\0'; // terminate the status line
- pszEOL += 2; // point to the rest of the buffer
-
- // set the status string first
- pResponse->pszStatus = strchr(pBuf, ' ');
- if (pResponse->pszStatus == NULL) {
- if (g_fLogging & NALOG_INFO0) {
- fprintf(g_log, "NewHTTPResponse_sz: er 4\n");
- fflush(g_log);
- }
- goto cleanup; // syntax error
+ // Make sure to compute extport *before* we zero tcpInfo->retries
+ extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo));
+ tcpInfo->retries = 0;
+ natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE);
}
- pResponse->pszStatus++; // point to the actual status
-
- pResponse->pszReason = strchr(pResponse->pszStatus, ' ');
- if (pResponse->pszReason == NULL) {
- if (g_fLogging & NALOG_INFO0) {
- fprintf(g_log, "NewHTTPResponse_sz: er 5\n");
- fflush(g_log);
- }
- goto cleanup; // syntax error
+mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo)
+ {
+ tcpLNTInfo **ptr = &m->tcpInfoUnmapList;
+ while (*ptr && *ptr != tcpInfo) ptr = &(*ptr)->next;
+ if (*ptr) { *ptr = (*ptr)->next; mDNSPlatformMemFree(tcpInfo); } // If we found it, cut it from our list and free the memory
}
- pResponse->pszReason[0] = '\0'; // terminate status string
- pResponse->pszReason++; // point to the reason string
-
- iNumHeaders = 0; // initialize to 0 headers
-
- // parse header fields line by line (while not end of headers)
- while (!fEOH) {
- PProperty pHeader = &(pResponse->aHeaders[iNumHeaders]);
- // point header field name to the first char of the line
- pHeader->pszName = pszEOL;
-
- // search for the end of line
- pszEOL = FindHTTPHeaderNewLine(pszEOL,
- iBufferSize - (pszEOL - pBuf), // remainder size
- &fEOH);
- if (pszEOL == NULL) {
- if (g_fLogging & NALOG_INFO0) {
- fprintf(g_log, "NewHTTPResponse_sz: er reading header field %d @ %lu / %lu\n",
- iNumHeaders, pHeader->pszName - pBuf, iBufferSize);
- DumpHex(pszHTTPResponse, iBufferSize);
- fflush(g_log);
- }
- goto cleanup; // syntax error
- }
-
- *pszEOL = '\0'; // terminate this string
- pszEOL += 2; // point to beginning of next line
-
- pHeader->pszValue = strchr(pHeader->pszName, ':');
- if (pHeader->pszValue == NULL) {
- if (g_fLogging & NALOG_INFO0) {
- fprintf(g_log, "NewHTTPResponse_sz: er 6\n");
- fflush(g_log);
- }
- goto cleanup; // syntax error (header field has no ":")
- }
-
- pHeader->pszValue[0] = '\0'; // terminate the header name string
- pHeader->pszValue++; // point after the ":"
- // get rid of leading spaces for the value part
- while (
- (pHeader->pszValue[0] == ' ') ||
- (pHeader->pszValue[0] == '\t') ||
- (pHeader->pszValue[0] == '\r') ||
- (pHeader->pszValue[0] == '\n')
- ) {
- pHeader->pszValue++; // skip the space
- }
+mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
+ {
+ mStatus status = mStatus_NoError;
+ tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context;
+ mDNSBool closed = mDNSfalse;
+ long n = 0;
+ long nsent = 0;
- iNumHeaders++; // added one more header
- pHeader++; // point to the next header in pResponse->aHeaders
- }
+ if (tcpInfo == mDNSNULL) { LogOperation("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }
- pResponse->iNumHeaders = iNumHeaders; // remember to set it in pResponse
-
- pResponse->pszBody = pszEOL + 2; // point after the empty line
-
- return pResponse;
-
-cleanup:
- if (pResponse->buf != NULL) free(pResponse->buf);
- free(pResponse);
- return NULL;
-}
-
-// DeleteHTTPResponse
-// Deallocates stuff in the HTTPResponse structure, effectively returning
-// memory to the system and destroying the structure.
-// NOTE: The pointer pResponse WILL BE FREED, and will be unusable after
-// the call to DeleteHTTPResponse.
-static void DeleteHTTPResponse(PHTTPResponse pResponse)
-{
-// int i;
-
- if (pResponse == NULL) return;
-
- // Current impl is just simple array - no need to free()
- //for (i = 0; i < pResponse->iNumHeaders; i++) {
- // free(pResponse->aHeaders[i]);
- //}
-
- if (pResponse->buf != NULL)
- free(pResponse->buf);
- free(pResponse);
-}
-
-//typedef struct tagHTTPResponse {
-// char *pszStatus;
-// char *pszReason;
-// int iNumHeaders;
-// Property aHeaders[30]; // assume at most this many headers
-// char *pszBody;
-//
-// // for admin use
-// int fFree;
-// char *buf;
-//} HTTPResponse, *PHTTPResponse, **PPHTTPResponse;
-
-static void PrintHTTPResponse(PHTTPResponse pResponse)
-{
- int i;
-
- if (g_fLogging & (NALOG_INFO1)) {
- if (pResponse == NULL) return;
- fprintf(g_log, " *** HTTP response begin *** \n");
- fprintf(g_log, " * status = [%s], reason = [%s] *\n",
- pResponse->pszStatus, pResponse->pszReason);
- for (i = 0; i < pResponse->iNumHeaders; i++) {
- fprintf(g_log, " * Header \"%s\" = [%s]\n",
- pResponse->aHeaders[i].pszName,
- pResponse->aHeaders[i].pszValue);
- }
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, " * body = [%s] *\n", pResponse->pszBody);
- fprintf(g_log, " *** HTTP response end *** \n");
- }
-}
-
-static int DiscoverRouter(PHTTPResponse pResponse)
-{
- int i;
- int fLocation = FALSE;
- int fUSN = FALSE;
- int fIsNATDevice = FALSE;
-
-#if 0
- if (strcmp(pResponse->pszStatus, "200") != 0)
- return -1;
-#endif
-
- if (pResponse == NULL) {
- if (g_fLogging & NALOG_INFO0)
- fprintf(g_log, "DiscoverRouter: pResponse == NULL\n");
- return -1;
- }
+ // The handlers below expect to be called with the lock held
+ mDNS_Lock(tcpInfo->m);
+
+ if (err) { LogOperation("tcpConnectionCallback: received error"); goto exit; }
- // check to see if this is a relevant packet
- for (i = 0; i < pResponse->iNumHeaders; i++) {
- PProperty pHeader = &(pResponse->aHeaders[i]);
-
- if ((strcasecmp(pHeader->pszName, "ST") == 0) ||
- (strcasecmp(pHeader->pszName, "NT") == 0)) {
- if ((strcmp(pHeader->pszValue,
- "urn:schemas-upnp-org:service:WANIPConnection:1") == 0) ||
- (strcmp(pHeader->pszValue,
- "urn:schemas-upnp-org:device:InternetGatewayDevice:1") == 0)) {
- fIsNATDevice = TRUE;
- }
+ if (ConnectionEstablished) // connection is established - send the message
+ {
+ LogOperation("tcpConnectionCallback: connection established, sending message");
+ nsent = mDNSPlatformWriteTCP(sock, (char *)tcpInfo->Request, tcpInfo->requestLen);
+ if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; }
}
- }
-
- // leave the message alone if we don't need it
- if (!fIsNATDevice)
- return -1;
-
- // Now that we know we're looking at the message about the NAT device:
- pthread_mutex_lock(&g_xUPnP);
-
- // set upnp to be unconfigured for now
- g_fUPnPEnabled = FALSE;
-
- // loop through the headers
- for (i = 0; i < pResponse->iNumHeaders; i++) {
- PProperty pHeader = &(pResponse->aHeaders[i]);
-
- if (strcasecmp(pHeader->pszName, "Location") == 0) {
- char *p;
- char *q;
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "Checking Location...\n");
- p = pHeader->pszValue;
- if (strncmp(p, "http://", 7) != 0)
- continue; // hope for another Location header to correct it
- p += 7; // skip over "http://"
- q = strchr(p, '/');
-
- // set the control URL first
- if (q == NULL) {
- g_szNATDevDescURL[0] = '/';
- g_szNATDevDescURL[1] = '\0';
- }
- else {
- strncpy(g_szNATDevDescURL, q, sizeof(g_szNATDevDescURL) - 1);
- g_szNATDevDescURL[sizeof(g_szNATDevDescURL) - 1] = '\0';
- // terminate the host/port string
- *q = '\0';
- }
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, " Device Description URL set to[%s]...\n",
- g_szNATDevDescURL);
+ else
+ {
+ n = mDNSPlatformReadTCP(sock, (char *)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
+ LogOperation("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
- // see if port is specified
- q = strchr(p, ':');
- if (q == NULL) {
- snprintf(g_szRouterHostPortDesc, sizeof(g_szRouterHostPortDesc), "%s", p);
+ if (n < 0) { LogOperation("tcpConnectionCallback - read returned %d", n); status = mStatus_ConnFailed; goto exit; }
+ else if (closed) { LogOperation("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; }
- g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p);
- g_saddrRouterDesc.sin_port = htons(80);
+ tcpInfo->nread += n;
+ LogOperation("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
+ if (tcpInfo->nread > LNT_MAXBUFSIZE)
+ {
+ LogOperation("result truncated...");
+ tcpInfo->nread = LNT_MAXBUFSIZE;
}
- else {
- // don't include the ":80" - HTTP is by default port 80
- if (atoi(q+1) == 80) *q = '\0';
-
- strlcpy(g_szRouterHostPortDesc, p, sizeof(g_szRouterHostPortDesc));
-
- // terminate the host part and point to it
- *q = '\0';
- q++;
- g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p);
- g_saddrRouterDesc.sin_port = htons(atoi(q));
+ switch (tcpInfo->op)
+ {
+ case LNTDiscoveryOp: handleLNTDeviceDescriptionResponse (tcpInfo); break;
+ case LNTExternalAddrOp: handleLNTGetExternalAddressResponse(tcpInfo); break;
+ case LNTPortMapOp: handleLNTPortMappingResponse (tcpInfo); break;
+ case LNTPortMapDeleteOp: status = mStatus_ConfigChanged; break;
+ default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break;
}
-
- g_saddrRouterDesc.sin_family = AF_INET;
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, " Router Address set to[%s]...\n",
- g_szRouterHostPortDesc);
- fLocation = TRUE;
}
- else if (strcasecmp(pHeader->pszName, "USN") == 0) {
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "Checking USN...\n");
- strncpy(g_szUSN, pHeader->pszValue, sizeof(g_szUSN) - 1);
- g_szUSN[sizeof(g_szUSN) - 1] = '\0';
- fUSN = TRUE;
- }
- else {
- ; // do nothing for other headers for now
- }
- }
-
- // now check flags and set enabled if all set
- if (fLocation && fUSN) {
- if (g_fLogging & NALOG_INFO1) {
- fprintf(g_log,
- "Description Host/port string: [%s]\n"
- "NATDevDescURL: [%s], USN: [%s]\n",
- g_szRouterHostPortDesc,
- g_szNATDevDescURL, g_szUSN);
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "Got router information\n");
- }
-
- g_fUPnPEnabled = TRUE;
- pthread_cond_broadcast(&g_condUPnP);
- }
-
- // remember to unlock before return
- pthread_mutex_unlock(&g_xUPnP);
-
- return 0;
-}
-
-// granularity is specified as: granularity = 1/nth seconds
-#define UPNP_TIMEOUT_GRANULARITY (1000)
-#define U_TOGRAN UPNP_TIMEOUT_GRANULARITY
-
-// result = a - b
-static void TimevalSubtract(
- struct timeval *result,
- const struct timeval *a,
- const struct timeval *b)
-{
- result->tv_sec = a->tv_sec - b->tv_sec;
-
- if (b->tv_usec > a->tv_usec) {
- result->tv_sec--;
- result->tv_usec = 1000000 + a->tv_usec - b->tv_usec;
- }
- else
- result->tv_usec = a->tv_usec - b->tv_usec;
-}
-
-// elapsed = end - start
-static void GetTimeElapsed(
- const struct timeval *tv_start,
- const struct timeval *tv_end,
- struct timeval *tv_elapsed)
-{
- TimevalSubtract(tv_elapsed, tv_end, tv_start);
-#if 0
- tv_elapsed->tv_sec = tv_end->tv_sec - tv_start->tv_sec;
-
- if (tv_start->tv_usec > tv_end->tv_usec) {
- tv_elapsed->tv_sec--;
- tv_elapsed->tv_usec = 1000000 + tv_end->tv_usec - tv_start->tv_usec;
- }
- else
- tv_elapsed->tv_usec = tv_end->tv_usec - tv_start->tv_usec;
-#endif
-}
-
-// returns +1, 0, or -1, if a>b, a==b, a<b, respectively
-static int CompareTime(
- const struct timeval *a,
- const struct timeval *b
- )
-{
- if ((a->tv_sec == b->tv_sec) &&
- (a->tv_usec == b->tv_usec)) return 0;
-
- if (a->tv_sec > b->tv_sec) return 1;
- else if (a->tv_sec < b->tv_sec) return -1;
-
- // if seconds are equal...
- if (a->tv_usec > b->tv_usec) return 1;
- else return -1;
-}
-
-static int WaitControlURLSet(double timeout)
-{
- struct timespec ts;
- struct timeval tv;
- struct timeval tv_start;
- int iRet;
- long to_sec = (int) (timeout / U_TOGRAN);
- long to_usec =
- (int) (((timeout / U_TOGRAN) - to_sec) * 1000000.0);
- //long to_sec = (int) timeout;
- //long to_usec = (int) ((timeout - to_sec) * 1000000.0);
- struct timeval elapsed;
-
- // get function start time
- gettimeofday(&tv_start, NULL);
-
- pthread_mutex_lock(&g_xUPnP);
-
-#if 0
- // if last update is too long ago then wait for it
- GetTimeElapsed(&g_tvLastUpdateTime, &tv_start, &elapsed);
- if ((elapsed.tv_sec + (elapsed.tv_usec / 1000000.0)) >
- (((double) g_iUPnPTimeout) / U_TOGRAN))
- g_fControlURLSet = 0;
-#endif
-
- while (!g_fControlURLSet) {
- // get current time
- gettimeofday(&tv, NULL);
-
-#if 0
-for now ignore device timeout
- // see if we've past the device's timeout first
- GetTimeElapsed(&g_tvUPnPInitTime, &tv, &elapsed);
- if ((elapsed.tv_sec > g_timeout_sec) ||
- ( (elapsed.tv_sec == g_timeout_sec) &&
- (elapsed.tv_usec > g_timeout_usec)
- ))
+exit:
+ if (err || status)
{
- pthread_mutex_unlock(&g_xUPnP);
- return FALSE;
- }
-#endif
-
- // calculate ts to sleep till
- ts.tv_sec = tv.tv_sec + to_sec;
- ts.tv_nsec = (tv.tv_usec + to_usec) * 1000;
- if (ts.tv_nsec > 1000000000) {
- ts.tv_nsec -= 1000000000;
- ts.tv_sec += 1;
- }
-
- // now get how long we've been in this function already and deduct
- GetTimeElapsed(&tv_start, &tv, &elapsed);
- ts.tv_sec -= elapsed.tv_sec;
- if (ts.tv_nsec < (elapsed.tv_usec * 1000)) {
- ts.tv_sec--;
- ts.tv_nsec = 1000000000 + ts.tv_nsec - (elapsed.tv_usec * 1000);
- }
- else {
- ts.tv_nsec -= (elapsed.tv_usec * 1000);
+ mDNSPlatformTCPCloseConnection(tcpInfo->sock);
+ tcpInfo->sock = mDNSNULL;
+ if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; }
+ if (tcpInfo->Reply ) { mDNSPlatformMemFree(tcpInfo->Reply); tcpInfo->Reply = mDNSNULL; }
}
- iRet = pthread_cond_timedwait(&g_condUPnPControlURL, &g_xUPnP, &ts);
+ if (tcpInfo) mDNS_Unlock(tcpInfo->m);
- // if timeout then return false
- if (iRet != 0)
- {
- pthread_mutex_unlock(&g_xUPnP);
- return FALSE;
- }
+ if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo);
}
- pthread_mutex_unlock(&g_xUPnP);
-
- return TRUE;
-}
-
-static int WaitUPnPFunction()
-{
- struct timeval start;
-// struct timeval end;
- double wait2;
-// struct timeval elapsed;
-
- gettimeofday(&start, NULL);
-
- wait2 = (double)g_iFunctionTimeout;
-
- WaitControlURLSet(wait2);
-//gettimeofday(&end, NULL);
-//GetTimeElapsed(&start, &end, &elapsed);
-//fprintf(stderr, "== wait2: (%f) %d.%06d\n",
-// wait2/U_TOGRAN, elapsed.tv_sec, elapsed.tv_usec);
-
- return g_fControlURLSet;
-}
-
-static void SetLocalIP();
-
-static int SendTCPMsg_saddr_parse(
- char *msg, int iLen,
- char *result, int resultSize,
- struct sockaddr_in *saHost);
-
-static void *TCPProc(void *in)
-{
- int iRet;
- unsigned char buf[MAX_SOAPMSGSIZE];
- int iBufLen;
-
- (void)in; // unused
- WaitUPnPFunction();
- //TracePrint(ELL_TRACE, "UPnP: Begin TCPProc\n");
-
- // do the subscription
+mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSAddr *const Addr, const mDNSIPPort Port, LNTOp_t op)
{
- char callback[100];
- char response[2000];
- PHTTPResponse resp;
- int n;
- snprintf(callback, sizeof(callback), "%u.%u.%u.%u:%u",
- ((uint8_t*)&g_dwLocalIP)[0], ((uint8_t*)&g_dwLocalIP)[1],
- ((uint8_t*)&g_dwLocalIP)[2], ((uint8_t*)&g_dwLocalIP)[3], g_wEventPort);
-
- n = snprintf((char *)buf, sizeof(buf),
- szEventMsgSubscribeFMT,
- g_szEventURL,
- callback, g_szRouterHostPortEvent, 1800);
-
- memset(response, 0, 2000);
- n = SendTCPMsg_saddr_parse(
- (char *)buf, n,
- response, 2000,
- &g_saddrRouterEvent);
- if (n > 0)
+ mStatus err = mStatus_NoError;
+ mDNSIPPort srcport = zeroIPPort;
+
+ if (mDNSIPv4AddressIsZero(Addr->ip.v4) || mDNSIPPortIsZero(Port))
+ { LogMsg("LNT MakeTCPConnection: bad address/port %#a:%d", Addr, mDNSVal16(Port)); return(mStatus_Invalid); }
+ info->m = m;
+ info->Address = *Addr;
+ info->Port = Port;
+ info->op = op;
+ info->nread = 0;
+ info->replyLen = LNT_MAXBUFSIZE;
+ if (info->Reply != mDNSNULL) mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE); // reuse previously allocated buffer
+ else if ((info->Reply = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogOperation("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
+
+ if (info->sock) { LogOperation("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
+ info->sock = mDNSPlatformTCPSocket(m, kTCPSocketFlags_Zero, &srcport);
+ if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); }
+ LogOperation("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
+ err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpConnectionCallback, info);
+
+ if (err == mStatus_ConnPending) err = mStatus_NoError;
+ else if (err == mStatus_ConnEstablished)
{
- response[n] = '\0';
- resp = NewHTTPResponse_sz((char *)response, n+1, TRUE);
- if (NULL != resp)
- {
-////TracePrint(ELL_TRACE, "UPnP Subscribe returns %s/%d\n", resp->pszStatus, n);
- }
- else
- {
-////TracePrint(ELL_TRACE, "UPnP Subscribe not enough response (%d) \n[%s]\n",
-// n, response);
- }
- DeleteHTTPResponse(resp);
+ mDNS_DropLockBeforeCallback();
+ tcpConnectionCallback(info->sock, info, mDNStrue, mStatus_NoError);
+ mDNS_ReclaimLockAfterCallback();
+ err = mStatus_NoError;
}
- else
+ else
{
-////TracePrint(ELL_TRACE, "UPnP Subscribe failed (%d)\n", n);
- return NULL;
+ LogMsg("LNT MakeTCPConnection: connection failed");
+ mDNSPlatformTCPCloseConnection(info->sock); // Dispose the socket we created with mDNSPlatformTCPSocket() above
+ info->sock = mDNSNULL;
+ mDNSPlatformMemFree(info->Reply);
+ info->Reply = mDNSNULL;
}
+ return(err);
}
- //TracePrint(ELL_TRACE, "UPnP: TCPProc begin loop\n");
-
- g_sTCPCancel = -1;
-
- for (;;)
+mDNSlocal unsigned int AddSOAPArguments(char *buf, unsigned int maxlen, int numArgs, Property *a)
{
-// ssize_t n;
- struct sockaddr_in recvaddr;
- socklen_t recvaddrlen;
- fd_set readfds;
- struct timeval timeout;
- int sEvent;
- int fFirstRecv;
- int sMax;
-
- // for after responding to long(?) TCP event
- if (g_fQuit)
- goto cleanup;
-
- if (g_sTCPCancel != -1) close(g_sTCPCancel);
- sMax = g_sTCPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sMax < g_sTCP) sMax = g_sTCP;
-
- FD_ZERO(&readfds);
- FD_SET(g_sTCP, &readfds);
- FD_SET(g_sTCPCancel, &readfds);
- iRet = select(sMax+1, &readfds, NULL, NULL, NULL);
- if (iRet <= 0) {
- if (EBADF == errno)
- continue;
- //TracePrint(ELL_TRACE, "UPnP Event select failed (%d)\n", errno);
- continue;
- }
-
- recvaddrlen = sizeof(recvaddr);
- sEvent = accept(g_sTCP, (struct sockaddr *)&recvaddr, &recvaddrlen);
- // not likely - (system's descriptor/file table full)
- if (sEvent <= 0) continue;
-
- ////TracePrint(ELL_TRACE, "UPnP receiving event..\n");
-
- // read all we could from this event
- fFirstRecv = 1;
- iBufLen = 0;
- for (;;)
+ static const char f1[] = "<%s>%s</%s>";
+ static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s</%s>";
+ int i, len = 0;
+ *buf = 0;
+ for (i = 0; i < numArgs; i++)
{
- FD_ZERO(&readfds);
- FD_SET(sEvent, &readfds);
- timeout.tv_sec = 0;
- timeout.tv_usec = 400000; // long cause we're dealing with input
- iRet = select(sEvent+1, &readfds, NULL, NULL, &timeout);
- if (iRet <= 0) {
- if (g_fQuit)
- {
- close(sEvent);
- goto cleanup;
- }
- break;
- }
-
- // recv
- iRet = recv(sEvent, buf + iBufLen, MAX_SOAPMSGSIZE - iBufLen, 0);
- if (iRet < 0)
- {
- // something is wrong
- break;
- }
- else if (iRet == 0)
- {
- break;
- }
-
- iBufLen += iRet;
-
- if (fFirstRecv)
- {
- int iTemp;
- iTemp = send(sEvent, HTTP200OK, HTTP200OKLEN, 0);
- shutdown(sEvent, 1);
- fFirstRecv = 0;
- }
+ if (a[i].type) len += mDNS_snprintf(buf + len, maxlen - len, f2, a[i].name, a[i].type, a[i].value, a[i].name);
+ else len += mDNS_snprintf(buf + len, maxlen - len, f1, a[i].name, a[i].value, a[i].name);
}
+ return(len);
+ }
- // now send 200 OK and be done
- close(sEvent);
-
- ////TracePrint(ELL_TRACE, "UPnP event (%d) received (%d)\n", g_fExpectEvent, iBufLen);
-
- // and parse the XML here.
- if (iBufLen < MAX_SOAPMSGSIZE)
+mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, char *Action, int numArgs, Property *Arguments, LNTOp_t op)
+ {
+ // SOAP message header format -
+ // - control URL
+ // - action (string)
+ // - router's host/port ("host:port")
+ // - content-length
+ static const char header[] =
+ "POST %s HTTP/1.1\r\n"
+ "Content-Type: text/xml; charset=\"utf-8\"\r\n"
+ "SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%s\"\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
+ "Host: %s\r\n"
+ "Content-Length: %d\r\n"
+ "Connection: close\r\n"
+ "Pragma: no-cache\r\n"
+ "\r\n"
+ "%s\r\n";
+
+ static const char body1[] =
+ "<?xml version=\"1.0\"?>\r\n"
+ "<SOAP-ENV:Envelope"
+ " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\""
+ " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ "<SOAP-ENV:Body>"
+ "<m:%s xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">";
+
+ static const char body2[] =
+ "</m:%s>"
+ "</SOAP-ENV:Body>"
+ "</SOAP-ENV:Envelope>\r\n";
+
+ mStatus err;
+ char body[2048]; // Typically requires 1110-1122 bytes, so 2048 allows a generous safety margin
+ int bodyLen;
+
+ if (m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL) // if no SOAP URL or address exists get out here
+ { LogOperation("SendSOAPMsgControlAction: no SOAP URL or address string"); return mStatus_Invalid; }
+
+ // Create body
+ bodyLen = mDNS_snprintf (body, sizeof(body), body1, Action);
+ bodyLen += AddSOAPArguments(body + bodyLen, sizeof(body) - bodyLen, numArgs, Arguments);
+ bodyLen += mDNS_snprintf (body + bodyLen, sizeof(body) - bodyLen, body2, Action);
+
+ // Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field
+ if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE);
+ if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; }
+ info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, Action, m->UPnPSOAPAddressString, bodyLen, body);
+
+ err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op);
+ if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; }
+ return err;
+ }
+
+// Build port mapping request with new port (up to max) and send it
+mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n)
+ {
+ char externalPort[6];
+ char internalPort[6];
+ char localIPAddrString[30];
+ char publicPortString[40];
+ Property propArgs[8];
+ mDNSu16 ReqPortNum = RequestedPortNum(n);
+ NATTraversalInfo *n2 = m->NATTraversals;
+
+ // Scan our m->NATTraversals list to make sure the external port we're requesting is locally unique.
+ // UPnP gateways will report conflicts if different devices request the same external port, but if two
+ // clients on the same device request the same external port the second one just stomps over the first.
+ // One way this can happen is like this:
+ // 1. Client A binds local port 80
+ // 2. Client A requests external port 80 -> internal port 80
+ // 3. UPnP NAT gateway refuses external port 80 (some other client already has it)
+ // 4. Client A tries again, and successfully gets external port 80 -> internal port 81
+ // 5. Client B on same machine tries to bind local port 80, and fails
+ // 6. Client B tries again, and successfully binds local port 81
+ // 7. Client B now requests external port 81 -> internal port 81
+ // 8. UPnP NAT gateway allows this, stomping over Client A's existing mapping
+
+ while (n2)
{
- buf[iBufLen] = '\0';
- // for now do nothing
- }
+ if (n2 == n || RequestedPortNum(n2) != ReqPortNum) n2=n2->next;
else
- {
- buf[MAX_SOAPMSGSIZE - 1] = '\0';
- }
- }
-
-cleanup:
- //TracePrint(ELL_TRACE, "UPnP: TCPProc end\n");
- close(g_sTCP);
- g_sTCP = -1;
- g_fEventEnabled = FALSE;
- if (g_sTCPCancel != -1) close(g_sTCPCancel);
- g_sTCPCancel = -1;
- return NULL;
-}
-
-static void *UDPProc(void *in)
-{
-// char fLoop = 0; // false - don't send copy to self
-// int iTTL = SSDP_TTL;
- int iRet;
-// struct ip_mreq mreq;
-// struct sockaddr_in saddr;
- unsigned char buf[65536];
-// FILE *log = g_log;
- static time_t last_getdevicedesc_t = 0;
-
- (void)in; // unused
- pthread_mutex_lock(&g_xUPnP);
- gettimeofday(&g_tvUPnPInitTime, NULL);
- pthread_mutex_unlock(&g_xUPnP);
-
- for (;;) {
- ssize_t n;
- struct sockaddr_in recvaddr;
- socklen_t recvaddrlen;
- fd_set readfds;
- //struct timeval timeout;
- //int i;
- int sMax;
-
- if (g_sUDPCancel < g_sUDP) sMax = g_sUDP;
- else sMax = g_sUDPCancel;
-
- FD_ZERO(&readfds);
- FD_SET(g_sUDP, &readfds);
- FD_SET(g_sUDPCancel, &readfds);
- iRet = select(sMax+1, &readfds, NULL, NULL, NULL);
-
- if (iRet <= 0) {
- if (g_fQuit)
- {
- close(g_sUDP);
- close(g_sUDPCancel);
- g_sUDP = -1;
- g_sUDPCancel = -1;
- return NULL;
- }
- continue;
- }
-
- if (!FD_ISSET(g_sUDP, &readfds)) continue;
- recvaddrlen = sizeof(recvaddr);
- n = recvfrom(g_sUDP, buf, sizeof(buf)-1, 0,
- (struct sockaddr *)&recvaddr, &recvaddrlen);
- if (n < 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "recv failed (%d)\n", errno);
- close(g_sUDP);
- close(g_sUDPCancel);
- g_sUDP = -1;
- g_sUDPCancel = -1;
- return NULL;
- }
- buf[n] = '\0';
- if (strncmp((char *)buf, "HTTP/1.1", 8) == 0) {
- PHTTPResponse pResponse = NewHTTPResponse_sz((char *)buf, n+1, TRUE);
- PrintHTTPResponse(pResponse);
- if (DiscoverRouter(pResponse) == 0)
{
- time_t now = time(NULL);
- if (!g_fControlURLSet ||
- ((now - last_getdevicedesc_t) > 5))
+ if (n->tcpInfo.retries < 100)
{
- GetDeviceDescription();
- SetLocalIP();
- last_getdevicedesc_t = now;
+ n->tcpInfo.retries++;
+ ReqPortNum = RequestedPortNum(n); // Pick a new port number
+ n2 = m->NATTraversals; // And re-scan the list looking for conflicts
}
- }
- DeleteHTTPResponse(pResponse);
- }
- else if (strncmp((char *)buf, "NOTIFY * HTTP/1.1", 7) == 0) {
- // temporarily use this to fudge - will have the exact same
- // parsing, only status/reason set to "*" and "HTTP/1.1".
- // TODO: add support for HTTP requests
- PHTTPResponse pResponse = NewHTTPResponse_sz((char *)buf, n+1, TRUE);
- if (DiscoverRouter(pResponse) == 0)
- {
- time_t now = time(NULL);
- if (!g_fControlURLSet ||
- ((now - last_getdevicedesc_t) > 5))
+ else
{
- GetDeviceDescription();
- SetLocalIP();
- last_getdevicedesc_t = now;
+ natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Refused, zeroIPPort, 0);
+ return mStatus_NoError;
}
}
- DeleteHTTPResponse(pResponse);
}
- else {
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, "(%ld) Buffer: \n[%s]\n", time(NULL), buf);
- fflush(g_log);
- }
- }
-
- close(g_sUDP);
- g_sUDP = -1;
-}
-
-static void SendUDPMsg(const char *msg) {
- struct sockaddr_in saSendTo;
- int iRet;
- int iLen;
-
- bzero(&saSendTo, sizeof(saSendTo));
- saSendTo.sin_family = AF_INET;
- saSendTo.sin_addr.s_addr = inet_addr(SSDP_IP);
- saSendTo.sin_port = htons(SSDP_PORT);
-
- iLen = strlen(msg);
-
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, "SendUDP: [%s]\n", msg);
-
- iRet = sendto(g_sUDP, msg, iLen, 0,
- (struct sockaddr *)&saSendTo, sizeof(saSendTo));
-
- // sanity check
- if (iRet != iLen)
- if (g_fLogging & NALOG_ALERT)
- fprintf(g_log,
- "SendUDPMsg: iRet(%d) != strlen(msg)(%d)! (errno %d)\n",
- iRet, iLen, errno);
-}
-
-// strstr, case insensitive, and is limited by len
-static char *strcasestr_n(const char *big, const char *little, int len)
-{
- int bigLen;
- int littleLen;
- int i;
- int end;
-
- if (little == NULL) return (char *)big;
- if (big == NULL) return NULL;
-
- //bigLen = strlen(big);
- bigLen = len;
- littleLen = strlen(little);
-
- if (bigLen < littleLen) return NULL;
-
- end = bigLen - littleLen;
- for (i = 0; i <= end; (i++), (big++)) {
- if (strncasecmp(big, little, littleLen) == 0)
- return (char *)big;
- }
-
- return NULL;
-}
-
-// this is strnstr, only portable
-static char *strstr_n(const char *big, const char *little, int len)
-{
- int iBigLen;
- int iLittleLen;
-
- (void)len; // unused
-
- if ((big == NULL) || (little == NULL)) return NULL;
-
- iBigLen = strlen(big);
- iLittleLen = strlen(little);
-
- // this part is basically strnstr, except this is portable
- for (;;) {
- if (iBigLen < iLittleLen)
- return NULL;
- if (strncmp(big, little, iLittleLen) == 0)
- return (char *)big;
- ++big;
- --iBigLen;
- }
-}
-
-// returns -1 for "not found"
-static int FindContentLength(char *pbuf, int iLen)
-{
- // non reusable HTTP header parsing code:
- // ----------------------------------------------
- char *p;
- int iResult;
-
- // find content length header
- p = strcasestr_n(pbuf, "\r\nContent-Length:", iLen);
- if (p == NULL) return -1;
-
- p += sizeof("\r\nContent-Length:") - 1; // minus '\0'
-
- iResult = atoi(p);
-
- return iResult;
- // ----------------------------------------------
-}
-
-// returns -1 for "not found"
-static int FindBody(char *pbuf, int iLen)
-{
- // non reusable HTTP header parsing code:
- // ----------------------------------------------
- char *p;
-// int iResult;
-
- // find the empty line
- p = strstr_n(pbuf, "\r\n\r\n", iLen);
- if (p == NULL) return -1;
-
- p += sizeof("\r\n\r\n") - 1; // minus '\0'
-
- return (p - pbuf);
- // ----------------------------------------------
-}
-
-static int SendTCPMsg_saddr_2part(
- char *msg, int iLen,
- char *msg2, int iLen2,
- char *result, int resultSize,
- struct sockaddr_in *saHost)
-{
- int s;
- struct sockaddr_in saSendTo;
- int iRet;
- int iBufLen;
- int fND;
- int fcntl_flags;
- int iRetcode;
- struct timeval tv;
- fd_set writefds;
-
- struct timeval tv_start;
- struct timeval tv_end;
- struct timeval tv_elapsed;
-
- int iContentLength = -1;
- int iBodyOffset = -1;
-
- gettimeofday(&tv_start, NULL);
-
- if (g_fUPnPEnabled != TRUE) {
-//TracePrint(ELL_TRACE, "UPnP not enabled\n");
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n");
- return NA_E_NOT_AVAILABLE;
- }
-
- s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (s == -1) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "Can't get TCP socket (%d)\n", errno);
- return NA_E_NET;
- }
- fND = 1;
- if (setsockopt(s, IPPROTO_IP, TCP_NODELAY, &fND, sizeof(fND)) != 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/2part: Can't set TCP_NODELAY option!\n");
- iRetcode = NA_E_NET;
- goto cleanup;
- }
-
- fcntl_flags = 0;
- fcntl_flags = fcntl(s, F_GETFL, 0);
- fcntl_flags |= O_NONBLOCK;
- if (fcntl(s, F_SETFL, fcntl_flags) != 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/2part: Can't set O_NONBLOCK option!\n");
- iRetcode = NA_E_NET;
- goto cleanup;
+ // create strings to use in the message
+ mDNS_snprintf(externalPort, sizeof(externalPort), "%u", ReqPortNum);
+ mDNS_snprintf(internalPort, sizeof(internalPort), "%u", mDNSVal16(n->IntPort));
+ mDNS_snprintf(publicPortString, sizeof(publicPortString), "iC%u", ReqPortNum);
+ mDNS_snprintf(localIPAddrString, sizeof(localIPAddrString), "%u.%u.%u.%u",
+ m->AdvertisedV4.ip.v4.b[0], m->AdvertisedV4.ip.v4.b[1], m->AdvertisedV4.ip.v4.b[2], m->AdvertisedV4.ip.v4.b[3]);
+
+ // build the message
+ mDNSPlatformMemZero(propArgs, sizeof(propArgs));
+ propArgs[0].name = "NewRemoteHost";
+ propArgs[0].type = "string";
+ propArgs[0].value = "";
+ propArgs[1].name = "NewExternalPort";
+ propArgs[1].type = "ui2";
+ propArgs[1].value = externalPort;
+ propArgs[2].name = "NewProtocol";
+ propArgs[2].type = "string";
+ propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
+ propArgs[3].name = "NewInternalPort";
+ propArgs[3].type = "ui2";
+ propArgs[3].value = internalPort;
+ propArgs[4].name = "NewInternalClient";
+ propArgs[4].type = "string";
+ propArgs[4].value = localIPAddrString;
+ propArgs[5].name = "NewEnabled";
+ propArgs[5].type = "boolean";
+ propArgs[5].value = "1";
+ propArgs[6].name = "NewPortMappingDescription";
+ propArgs[6].type = "string";
+ propArgs[6].value = publicPortString;
+ propArgs[7].name = "NewLeaseDuration";
+ propArgs[7].type = "ui4";
+ propArgs[7].value = "0";
+
+ LogOperation("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum);
+ return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp);
+ }
+
+mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n)
+ {
+ LogOperation("LNT_MapPort");
+ if (n->tcpInfo.sock) return(mStatus_NoError); // If we already have a connection up don't make another request for the same thing
+ n->tcpInfo.parentNATInfo = n;
+ n->tcpInfo.retries = 0;
+ return SendPortMapRequest(m, n);
}
- if (saHost == NULL)
- memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo));
- else
- memcpy(&saSendTo, saHost, sizeof(saSendTo));
-
- iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo));
- if ((iRet < 0) && (errno != EINPROGRESS)) {
-//TracePrint(ELL_TRACE, "UPnP connect failed\n");
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/2part: connect failed (%d)\n", errno);
- iRetcode = NA_E_NET;
- goto cleanup;
- }
+mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n)
+ {
+ char externalPort[10];
+ Property propArgs[3];
+ tcpLNTInfo *info;
+ tcpLNTInfo **infoPtr = &m->tcpInfoUnmapList;
+ mStatus err;
+
+ // If no NAT gateway to talk to, no need to do all this work for nothing
+ if (!m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError;
+
+ mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort));
+
+ mDNSPlatformMemZero(propArgs, sizeof(propArgs));
+ propArgs[0].name = "NewRemoteHost";
+ propArgs[0].type = "string";
+ propArgs[0].value = "";
+ propArgs[1].name = "NewExternalPort";
+ propArgs[1].type = "ui2";
+ propArgs[1].value = externalPort;
+ propArgs[2].name = "NewProtocol";
+ propArgs[2].type = "string";
+ propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
+
+ n->tcpInfo.parentNATInfo = n;
+
+ // clean up previous port mapping requests and allocations
+ if (n->tcpInfo.sock) LogOperation("LNT_UnmapPort: closing previous open connection");
+ if (n->tcpInfo.sock ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; }
+ if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request); n->tcpInfo.Request = mDNSNULL; }
+ if (n->tcpInfo.Reply ) { mDNSPlatformMemFree(n->tcpInfo.Reply); n->tcpInfo.Reply = mDNSNULL; }
+
+ // make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns)
+ if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL)
+ { LogOperation("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
+ *info = n->tcpInfo;
+
+ while (*infoPtr) infoPtr = &(*infoPtr)->next; // find the end of the list
+ *infoPtr = info; // append
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log,
- "- Before Sending TCP Msg1: %d == %lu?\n", iLen, strlen(msg));
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, "Sending TCP msg part 1:\n[%s]\n", msg);
-
- tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
- tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
- FD_ZERO(&writefds);
- FD_SET(s, &writefds);
- iRet = select(s+1, 0, &writefds, 0, &tv);
- if (iRet < 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/2part: select failed (%d)\n", errno);
- iRetcode = NA_E_NET;
- goto cleanup;
- }
- if (iRet == 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/2part: select timed out\n");
- iRetcode = NA_E_TIMEOUT;
-gettimeofday(&tv_end, NULL);
-GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-//TracePrint(ELL_TRACE, "UPnP 2part: timeout @1st after %lu.%06lu secs\n",
-// tv_elapsed.tv_sec, tv_elapsed.tv_usec);
- goto cleanup;
+ err = SendSOAPMsgControlAction(m, info, "DeletePortMapping", 3, propArgs, LNTPortMapDeleteOp);
+ if (err) DisposeInfoFromUnmapList(m, info);
+ return err;
}
- iRet = send(s, msg, iLen, 0);
- // sanity check
- if (iRet != iLen)
- if (g_fLogging & NALOG_ALERT)
- fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg)(%d)!\n",
- iRet, iLen);
-
-//TracePrint(ELL_TRACE, "UPnP 2part: 1st %d == %d (%d) (%d)?\n", iRet, iLen, strlen(msg), errno);
-
- tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
- tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
- FD_ZERO(&writefds);
- FD_SET(s, &writefds);
- // calculate how much time elapsed
- gettimeofday(&tv_end, NULL);
- GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
- if (CompareTime(&tv_elapsed, &tv) > 0) {
- close(s);
- return NA_E_TIMEOUT;
- //tv.tv_sec = 0;
- //tv.tv_usec = 0;
- }
- else {
- // subtract that from timeout accordingly
- tv.tv_sec -= tv_elapsed.tv_sec;
- if (tv.tv_usec < tv_elapsed.tv_usec) {
- tv.tv_sec--;
- tv.tv_usec = 1000000 + tv.tv_usec - tv_elapsed.tv_usec;
- }
- else
- tv.tv_usec = tv.tv_usec - tv_elapsed.tv_usec;
- }
- iRet = select(s+1, 0, &writefds, 0, &tv);
- if (iRet < 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/2part: select2 failed (%d)\n", errno);
- iRetcode = NA_E_NET;
- goto cleanup;
- }
- if (iRet == 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/2part: select2 timed out\n");
- iRetcode = NA_E_TIMEOUT;
-gettimeofday(&tv_end, NULL);
-GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-//TracePrint(ELL_TRACE, "UPnP 2part: timeout @2nd after %lu.%06lu secs\n",
-// tv_elapsed.tv_sec, tv_elapsed.tv_usec);
- goto cleanup;
+mDNSexport mStatus LNT_GetExternalAddress(mDNS *m)
+ {
+ return SendSOAPMsgControlAction(m, &m->tcpAddrInfo, "GetExternalIPAddress", 0, mDNSNULL, LNTExternalAddrOp);
}
- iRet = send(s, msg2, iLen2, 0);
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log,
- "SendTCPMsg/parse: Before Sending TCP Msg2: %d == %lu?\n",
- iLen2, strlen(msg2));
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, "Sending TCP msg part 2:\n[%s]\n", msg2);
-
-//TracePrint(ELL_TRACE, "UPnP 2part: 2nd %d == %d (%d) (%d)?\n", iRet, iLen2, strlen(msg2), errno);
-
- // sanity check
- if (iRet != iLen2)
- if (g_fLogging & NALOG_ALERT)
- fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg2)(%d)!\n",
- iRet, iLen2);
-
- if (result == NULL) { // if caller just want to send/display msgs
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, "TCP Buffer: [");
- }
+mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info)
+ {
+ // Device description format -
+ // - device description URL
+ // - host/port
+ static const char szSSDPMsgDescribeDeviceFMT[] =
+ "GET %s HTTP/1.1\r\n"
+ "Accept: text/xml, application/xml\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
+ "Host: %s\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogOperation("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); }
+
+ // build message
+ if (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer
+ else if ((info->Request = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogOperation("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); }
+ info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString);
+ LogOperation("Describe Device: [%s]", info->Request);
+ return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp);
+ }
+
+// This function parses the response to our SSDP discovery message. Basically, we look to make sure this is a response
+// referencing a service we care about (WANIPConnection), then look for the "Location:" header and copy the addressing and
+// URL info we need.
+mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len)
+ {
+ char *ptr = (char *)data;
+ char *end = (char *)data + len;
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "start recv @%lu\n", time(NULL));
-
- iBufLen = 0;
- iContentLength = -1;
- iBodyOffset = -1;
- for (;;) {
- fd_set readfds;
- struct timeval timeout;
- int i;
-
- FD_ZERO(&readfds);
- FD_SET(s, &readfds);
-
- // In testing, the Linksys Wireless-G Broadband Router "WRT54GS" takes
- // up to four seconds to respond, and even then only a partial response,
- // with the remainder coming in a second TCP segment half a second later.
- // Accordingly, we wait up to five seconds for the initial data, and then after that
- // wait one second after subsequent TCP segments, in care more data is still coming.
- timeout.tv_sec = iBufLen ? 1 : 5;
- timeout.tv_usec = 0;
- iRet = select(s+1, &readfds, NULL, NULL, &timeout);
- if (iRet <= 0)
+ // The formatting of the HTTP header is not always the same when it comes to the placement of
+ // the service and location strings, so we just look for each of them from the beginning for every response
+
+ // figure out if this is a message from a service we care about
+ while (ptr && ptr != end)
{
-//TracePrint(ELL_TRACE, "UPnP 2part: select timeout? (%d, %d)\n",
-// iRet, errno);
- break;
+ if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break; // find the first 'W'; is this WANIPConnection? if not, keep looking
+ ptr++;
}
+ if (ptr == mDNSNULL || ptr == end) return; // not a message we care about
-//gettimeofday(&tv_end, NULL);
-//GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-//fprintf(stderr, "2 == loop: %d.%06d\n", tv_elapsed.tv_sec, tv_elapsed.tv_usec);
-
- // if only sending messages
- if (result == NULL) {
- char t[1000];
- i = recv(s, t, 1000-1, 0); // leave room for '\0' for dump
- if (i== 0) break;
- if (g_fLogging & NALOG_DUMP) {
- t[i] = '\0';
- fprintf(g_log, "%s", t);
- }
- continue;
- }
-
- // EO result buf: discard extra bytes
- if (resultSize <= iBufLen) {
- char t[1000];
- i = recv(s, &t, 1000, 0);
- if (i== 0) break;
- // Note that there's no dump here - prevents DoS attack from
- // flooding the logs/diskspace
- continue;
- }
-
- i = recv(s, result + iBufLen, resultSize - iBufLen, 0);
- if (i <= 0) {
-//TracePrint(ELL_TRACE, "UPnP 2part: recv done %d (%d, %d)\n",
-// iBufLen, i, errno);
- break;
- }
-
- iBufLen += i;
-
- // parse and see if we can find content-length to quit early
- iContentLength = FindContentLength(result, iBufLen);
-
- // now if we're still in header, see if we can find body
- iBodyOffset = FindBody(result, iBufLen);
-
- // now check if we can leave early. conditions are:
- // past headers, and we've already recv'ed content-length of body
- if ((iBodyOffset >= 0) &&
- (iContentLength >= 0) &&
- ((iBufLen - iBodyOffset) >= iContentLength))
+ // find "Location:", starting from the beginning
+ ptr = (char *)data;
+ while (ptr && ptr != end)
{
-//TracePrint(ELL_TRACE, "UPnP 2part: read all specified %d (%d, %d) (%d, %d)\n",
-// iBufLen, i, errno, iBodyOffset, iContentLength);
- break;
- }
- }
-
-//fprintf(stderr, "2 -- \n");
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "SendTCPMsg_saddr_2part done recv %d @ %lu\n", iBufLen, time(NULL));
-
- if (result == NULL) { // if caller just want to send/display msgs
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, "]\n");
- }
-
- close(s);
- return iBufLen;
-
-cleanup:
- close(s);
- return iRetcode;
-}
-
-static int SendTCPMsg_saddr_parse(
- char *msg, int iLen,
- char *result, int resultSize,
- struct sockaddr_in *saHost)
-{
- int s;
- struct sockaddr_in saSendTo;
- int iRet;
- int iBufLen;
- int fcntl_flags;
- fd_set writefds;
- struct timeval tv;
-
- struct timeval tv_start;
-// struct timeval tv_end;
-// struct timeval tv_elapsed;
-
- // HTTP parsing vars
- char *pszCurHdr;
- int iContentLength;
- int iBodyOffset;
-// char prevChar;
-
- tv.tv_sec = 0;
- tv.tv_usec = 25000;
- select(0, NULL, NULL, NULL, &tv);
-
- pthread_mutex_lock(&g_xUPnPMsg);
-
- gettimeofday(&tv_start, NULL);
-
- if (g_fUPnPEnabled != TRUE) {
-//TracePrint(ELL_TRACE, "UPnP not enabled\n");
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n");
- pthread_mutex_unlock(&g_xUPnPMsg);
- return NA_E_NOT_AVAILABLE;
- }
-
- s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (s == -1) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "Can't get TCP socket (%d)\n", errno);
- pthread_mutex_unlock(&g_xUPnPMsg);
- return NA_E_NET;
- }
-
- fcntl_flags = 0;
- fcntl_flags = fcntl(s, F_GETFL, 0);
- fcntl_flags |= O_NONBLOCK;
- if (fcntl(s, F_SETFL, fcntl_flags) != 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/parse: Can't set O_NONBLOCK option!\n");
- close(s);
- pthread_mutex_unlock(&g_xUPnPMsg);
- return NA_E_NET;
- }
-
- if (saHost == NULL)
- memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo));
- else
- memcpy(&saSendTo, saHost, sizeof(saSendTo));
-
- iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo));
- if ((iRet < 0) && (errno != EINPROGRESS)) {
-//TracePrint(ELL_TRACE, "UPnP connect failed\n");
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/parse: connect failed (%d)\n", errno);
- close(s);
- pthread_mutex_unlock(&g_xUPnPMsg);
- return NA_E_NET;
- }
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "SendTCPMsg_saddr_parse: Before Sending TCP Msg: %d == %lu?\n",
- iLen, strlen(msg));
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log,"Sending TCP msg:\n[%s]\n", msg);
-
- tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
- tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
- FD_ZERO(&writefds);
- FD_SET(s, &writefds);
- iRet = select(s+1, 0, &writefds, 0, &tv);
- if (iRet < 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/parse: select failed (%d)\n", errno);
- close(s);
- pthread_mutex_unlock(&g_xUPnPMsg);
- return NA_E_NET;
- }
- if (iRet == 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "SendTCPMsg/parse: select timed out\n");
- close(s);
- pthread_mutex_unlock(&g_xUPnPMsg);
- return NA_E_TIMEOUT;
- }
-
- iRet = send(s, msg, iLen, 0);
-
- // sanity check
- if (iRet != iLen)
- if (g_fLogging & NALOG_ALERT)
- fprintf(g_log, "SendTCPMsg: iRet (%d) != strlen(msg) (%d)!\n",
- iRet, iLen);
-
- if (result == NULL) { // if caller just want to send/display msgs
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, "TCP Buffer: [");
- }
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "start recv @%lu\n", time(NULL));
-
- iBufLen = 0;
- pszCurHdr = result;
- iContentLength = -1;
- iBodyOffset = -1;
- for (;;) {
- fd_set readfds;
- struct timeval timeout;
- int i;
-
- FD_ZERO(&readfds);
- FD_SET(s, &readfds);
-
- // In testing, the Linksys Wireless-G Broadband Router "WRT54GS" takes
- // up to four seconds to respond, and even then only a partial response,
- // with the remainder coming in a second TCP segment half a second later.
- // Accordingly, we wait up to five seconds for the initial data, and then after that
- // wait one second after subsequent TCP segments, in care more data is still coming.
- timeout.tv_sec = iBufLen ? 1 : 5;
- timeout.tv_usec = 0;
- iRet = select(s+1, &readfds, NULL, NULL, &timeout);
- if (iRet <= 0) {
-//fprintf(stderr, "**********: select failed (%d/%d)\n", iRet, errno);
- break;
- }
-
-//gettimeofday(&tv_end, NULL);
-//GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
-//fprintf(stderr, "p == loop: %d.%06d\n", tv_elapsed.tv_sec, tv_elapsed.tv_usec);
-
- // if only sending messages
- if (result == NULL) {
- char t[1000];
- i = recv(s, t, 1000-1, 0); // leave room for '\0' for dump
- if (i== 0) break;
- if (g_fLogging & NALOG_DUMP) {
- t[i] = '\0';
- fprintf(g_log, "%s", t);
- }
- continue;
- }
-
- // EO result buf: discard extra bytes
- if (resultSize <= iBufLen) {
- char t[1000];
- i = recv(s, &t, 1000, 0);
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "SendTCPMsg_saddr_parse discarding %d bytes\n", i);
- if (i== 0) break;
- // Note that there's no dump here - prevents DoS attack from
- // flooding the logs/diskspace
- continue;
- }
-
- i = recv(s, result + iBufLen, resultSize - iBufLen, 0);
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "SendTCPMsg_saddr_parse read %d bytes (%d/%d)\n", i, iBufLen, resultSize);
- if (0 == i) {
-
- break;
- }
- else if (i < 0) {
- if (EAGAIN == errno) continue;
- break;
- }
-
- iBufLen += i;
-
- // parse and see if we can find content-length to quit early
- iContentLength = FindContentLength(result, iBufLen);
-
- // now if we're still in header, see if we can find body
- iBodyOffset = FindBody(result, iBufLen);
-
- }
-
-//fprintf(stderr, "p -- \n");
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "SendTCPMsg_saddr_parse done recv %d @ %lu\n", iBufLen, time(NULL));
-
- if (result == NULL) { // if caller just want to send/display msgs
- if (g_fLogging & NALOG_DUMP)
- fprintf(g_log, "]\n");
- }
-
- close(s);
- pthread_mutex_unlock(&g_xUPnPMsg);
- return iBufLen;
-}
-
-
-
-// szSOAPMsgControlAHeaderFMT - 4 args (ctrl_url, host/port, action, length)
-// szSOAPMsgControlABodyFMT - 2 args (action, args string)
-// szSOAPMsgControlAArgumentFMT - 2 args (name/value)
-static PHTTPResponse SendSOAPMsgControlAction(
- char *action,
- int argc,
- PProperty args,
- int f2Part)
-{
- //char outBuffer[65536];
- //char outBufferBody[65536];
- //char outBufferArgs[65536];
- char *outBuffer = NULL;
- char *outBufferBody = NULL;
- char *outBufferArgs = NULL;
- char *inBuffer = NULL;
- int iLen;
- int iHeaderLen;
- int iBodyLen;
- int iArgsLen;
- int iResultLen;
- int i;
- int n;
- PHTTPResponse pResponse = NULL;
-
-
- if (!WaitUPnPFunction())
- return NULL;
-
- if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "can't malloc for outBuffer\n");
- goto cleanup;
- }
- if ((outBufferBody = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "can't malloc for outBufferBody\n");
- goto cleanup;
- }
- if ((outBufferArgs = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "can't malloc for outBufferArgs\n");
- goto cleanup;
- }
- if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "can't malloc for inBuffer\n");
- goto cleanup;
- }
-
- iArgsLen = 0;
- if (args != NULL)
- for (i=0; i<argc; i++) {
- n = 0;
- if (args[i].pszType == NULL) {
- n = snprintf(outBufferArgs + iArgsLen, MAX_SOAPMSGSIZE - iArgsLen,
- szSOAPMsgControlAArgumentFMT,
- args[i].pszName, args[i].pszValue);
- }
- else {
- n = snprintf(outBufferArgs + iArgsLen, MAX_SOAPMSGSIZE - iArgsLen,
- szSOAPMsgControlAArgumentFMT_t,
- args[i].pszName, args[i].pszValue, args[i].pszType);
- }
- iArgsLen += n;
- }
- outBufferArgs[iArgsLen] = '\0';
-
- iBodyLen = snprintf(outBufferBody, MAX_SOAPMSGSIZE, szSOAPMsgControlABodyFMT,
- action, outBufferArgs);
-
- iHeaderLen = snprintf(outBuffer, MAX_SOAPMSGSIZE, szSOAPMsgControlAHeaderFMT,
- g_szControlURL, g_szRouterHostPortSOAP, action, iBodyLen);
-
- if (f2Part) {
- DumpHex(outBuffer, iHeaderLen+1);
- DumpHex(outBufferBody, iBodyLen+1);
- iResultLen = SendTCPMsg_saddr_2part(
- outBuffer, iHeaderLen,
- outBufferBody, iBodyLen,
- inBuffer, MAX_SOAPMSGSIZE,
- &g_saddrRouterSOAP);
- }
- else {
- strlcpy(outBuffer + iHeaderLen, outBufferBody, MAX_SOAPMSGSIZE - iHeaderLen);
- iLen = iHeaderLen + iBodyLen;
-
- DumpHex(outBuffer, iLen+1);
-
-//strcat(outBuffer, CRLF "0" CRLF CRLF);
-//iLen += 7;
-
- iResultLen = SendTCPMsg_saddr_parse(
- outBuffer, iLen,
- inBuffer, MAX_SOAPMSGSIZE,
- &g_saddrRouterSOAP);
- }
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "SendSOAPMsgControlAction iResultLen %d\n", iResultLen);
- if (iResultLen > 0) {
- if (iResultLen > MAX_SOAPMSGSIZE) {
- if (g_fLogging & NALOG_ALERT)
- fprintf(g_log, "result truncated..\n");
- iResultLen = MAX_SOAPMSGSIZE;
- }
- pResponse = NewHTTPResponse_sz(inBuffer, iResultLen, FALSE);
- if (pResponse != NULL) {
- PrintHTTPResponse(pResponse);
- //DeleteHTTPResponse(pResponse);
- // - return response to caller
- }
- }
- else {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "No TCP Response\n");
- //TracePrint(ELL_TRACE, "UPnP SendSOAPMsg got no TCP response (%d)\n",
-// iResultLen);
- }
-
-cleanup:
- if (outBuffer != NULL) free(outBuffer);
- if (outBufferBody != NULL) free(outBufferBody);
- if (outBufferArgs != NULL) free(outBufferArgs);
- if (inBuffer != NULL) free(inBuffer);
-
- return pResponse;
-}
-
-static int FindURLBase(char *pbuf, int iLen, char *szURLBase)
-{
- // non reusable XML parsing code:
- // ----------------------------------------------
- char *p;
- int i = 0;
-
- // now skip after end of this tag, then skip until controlURL tag
- p = strstr_n(pbuf, "<URLBase>", iLen);
- if (p == NULL) return -1;
-
- // skip to the actual stuff
- p += sizeof("<URLBase>") - 1; // minus '\0'
-
- // skip white spaces (just in case)
- while (isspace(*p))
- p++;
-
- // copy into szURLBase
- while ((*p != '\0') && (*p != '<') && !isspace(*p)) {
- if (i++ > 1000) break;
- *szURLBase = *p;
- szURLBase++;
- p++;
- }
- *szURLBase = '\0';
-
- return 0;
- // ----------------------------------------------
-}
-
-
-static int FindDescInfo(
- char *pbuf,
- int iLen,
- const char *szParentName,
- const char *szName,
- char *szValue)
-{
- char *p;
- char szSearch[100];
- int iSearchLen;
- int i = 0;
-
- // find the device within pbuf
- p = strstr_n(
- pbuf,
- szParentName,
- iLen);
- if (p == NULL)
- return -1;
-
- // adjust strlen
- iLen -= (p - pbuf);
- pbuf = p;
-
- // now skip after end of this tag, then skip until manufacturer tag
- iSearchLen = snprintf(szSearch, sizeof(szSearch), "<%s>", szName);
- p = strstr_n(pbuf, szSearch, iLen);
- if (p == NULL) return -1;
- p += iSearchLen;
-
- // skip white spaces (just in case)
- while (isspace(*p))
- p++;
-
- // copy into szValue
- while ((*p != '\0') && (*p != '<')) {
- if (i++ > 1000) break;
- *szValue = *p;
- szValue++;
- p++;
- }
- *szValue = '\0';
-
- return 0;
-}
-
-static int FindIGDInfo(char *pbuf, int iLen, const char *szName, char *szValue)
-{
- return FindDescInfo(
- pbuf, iLen,
- "urn:schemas-upnp-org:device:InternetGatewayDevice:1",
- szName, szValue);
-}
-
-static int FindManufacturer(char *pbuf, int iLen, char *szManuf)
-{
- return FindIGDInfo(pbuf, iLen, "manufacturer", szManuf);
-}
-
-static int FindFriendlyName(char *pbuf, int iLen, char *szValue)
-{
- return FindIGDInfo(pbuf, iLen, "friendlyName", szValue);
-}
-
-static int FindModelName(char *pbuf, int iLen, char *szValue)
-{
- return FindIGDInfo(pbuf, iLen, "modelName", szValue);
-}
-
-static int FindModelDescription(char *pbuf, int iLen, char *szValue)
-{
- return FindIGDInfo(pbuf, iLen, "modelDescription", szValue);
-}
-
-static int FindWANIPInfo(char *pbuf, int iLen, const char *szName, char *szValue)
-{
- return FindDescInfo(
- pbuf, iLen,
- "urn:schemas-upnp-org:service:WANIPConnection:1",
- szName, szValue);
-}
-
-static int FindControlURL(char *pbuf, int iLen, char *szControlURL)
-{
- return FindWANIPInfo(pbuf, iLen, "controlURL", szControlURL);
-}
-
-static int FindEventURL(char *pbuf, int iLen, char *szEventURL)
-{
- return FindWANIPInfo(pbuf, iLen, "eventSubURL", szEventURL);
-}
-
-static int FindRouterInfo(char *inBuffer, int iLen)
-{
- if (FindManufacturer(inBuffer, iLen, g_szManufacturer) != 0)
- g_szManufacturer[0] = '\0';
-
- if (FindFriendlyName(inBuffer, iLen, g_szFriendlyName) != 0)
- g_szFriendlyName[0] = '\0';
-
- if (FindModelName(inBuffer, iLen, g_szModelName) != 0)
- g_szModelName[0] = '\0';
-
- if (FindModelDescription(inBuffer, iLen, g_szModelDescription) != 0)
- g_szModelDescription[0] = '\0';
-
-//TracePrint(ELL_TRACE,
-// "UPnP Router Info:\n"
-// " - manufacturer [%s]\n"
-// " - friendly name [%s]\n"
-// " - model name [%s]\n"
-// " - model desc [%s]\n",
-// g_szManufacturer, g_szFriendlyName, g_szModelName, g_szModelDescription);
-
- return 0;
-}
-
-static void ParseURL(
- const char *szBuf,
- char *pszHostPort, int pszHostPort_size,
- struct sockaddr_in *psaddr,
- char *pszPath, int pszPath_size)
-{
- char buf[1024];
- char *p;
- char *q;
- unsigned short port;
-
- strlcpy(buf, szBuf, sizeof(buf));
-
- p = buf;
- if (0 == strncmp(p, "http://", 7))
- p += 7;
-
- q = strchr(p, '/');
-
- if (pszPath) {
- if (NULL == q) {
- pszPath[0] = '/';
- pszPath[1] = '\0';
- }
- else {
- strlcpy(pszPath, q, pszPath_size);
- *q = '\0';
+ if (*ptr == 'L' && (strncasecmp(ptr, "Location", 8) == 0)) break; // find the first 'L'; is this Location? if not, keep looking
+ ptr++;
}
- }
-
- // find the port separetor
- q = strchr(p, ':');
- if (NULL == q)
- port = 80;
- else {
- port = atoi(q + 1);
- // HTTP's by default port 80, so don't have it in the "Host:" header
- if (80 == port) *q = '\0';
- }
-
- if (pszHostPort) strlcpy(pszHostPort, p, pszHostPort_size);
-
- if (NULL != q) *q = '\0';
-
- if (NULL != psaddr) {
- psaddr->sin_family = AF_INET;
- psaddr->sin_addr.s_addr = inet_addr(p);
- psaddr->sin_port = htons(port);
- }
-#if 0
-//TracePrint(ELL_TRACE, "ParseURL [%s] -> [%s][%s] %lu.%lu.%lu.%lu:%u\n",
- szBuf,
- pszHostPort?pszHostPort:"",
- pszPath?pszPath:"",
- ((uint8_t*)&psaddr->sin_addr.s_addr)[0], ((uint8_t*)&psaddr->sin_addr.s_addr)[1],
- ((uint8_t*)&psaddr->sin_addr.s_addr)[2], ((uint8_t*)&psaddr->sin_addr.s_addr)[3],
- psaddr->sin_port);
-#endif
-}
-
-static void GetDeviceDescription(void)
-{
- char *outBuffer = NULL;
- char *inBuffer = NULL;
- int iBufLen;
- int iLen;
- char szURLBase[1024];
- char szControlURL[1024];
- char szEventURL[1024];
-
- if (!g_fUPnPEnabled) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "GetDeviceDescription: upnp not enabled\n");
- return;
- }
-
- if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "can't malloc for outBuffer\n");
- goto cleanup;
- }
- if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "can't malloc for inBuffer\n");
- goto cleanup;
- }
-
- iBufLen = snprintf(outBuffer, MAX_SOAPMSGSIZE, szSSDPMsgDescribeDeviceFMT, g_szNATDevDescURL,
- g_szRouterHostPortDesc);
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "Describe Device: [%s]\n", outBuffer);
- iLen = SendTCPMsg_saddr_parse(outBuffer, iBufLen, inBuffer, MAX_SOAPMSGSIZE,
- &g_saddrRouterDesc);
-
- if (iLen < 1) goto cleanup;
-
- g_fControlURLSet = FALSE;
-
- if (FindControlURL(inBuffer, iLen, szControlURL) != 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(g_log, "GetDeviceDesc: can't find control URL\n");
- goto cleanup;
- }
-
- // start modifying global
- pthread_mutex_lock(&g_xUPnP);
-
- {
- // now see if there's the URLBase
- if (FindURLBase(inBuffer, iLen, szURLBase) != 0) {
- // not there? try default numbers from device description
- memcpy(&g_saddrRouterBase, &g_saddrRouterDesc,
- sizeof(g_saddrRouterBase));
- strlcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc, sizeof(g_szRouterHostPortBase));
- }
- else {
- ParseURL(szURLBase,
- g_szRouterHostPortBase, sizeof(g_szRouterHostPortBase),
- &g_saddrRouterBase, NULL, 0);
-
- if ((strlen(g_szRouterHostPortBase) == 0) ||
- (g_saddrRouterBase.sin_addr.s_addr == INADDR_NONE)) {
- memcpy(&g_saddrRouterBase, &g_saddrRouterDesc,
- sizeof(g_saddrRouterBase));
- strlcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc, sizeof(g_szRouterHostPortBase));
- }
- }
- }
-
- ParseURL(szControlURL,
- g_szRouterHostPortSOAP, sizeof(g_szRouterHostPortSOAP), &g_saddrRouterSOAP, g_szControlURL, sizeof(g_szControlURL));
- if ((strlen(g_szRouterHostPortSOAP) == 0) ||
- (g_saddrRouterSOAP.sin_addr.s_addr == INADDR_NONE)) {
- memcpy(&g_saddrRouterSOAP, &g_saddrRouterBase,
- sizeof(g_saddrRouterSOAP));
- strlcpy(g_szRouterHostPortSOAP, g_szRouterHostPortBase, sizeof(g_szRouterHostPortSOAP));
- }
-
-
-////TracePrint(ELL_TRACE, "UPnP Control URL set to[%s][%s]...\n",
-// g_szRouterHostPortSOAP, g_szControlURL);
-
- g_fControlURLSet = TRUE;
- gettimeofday(&g_tvLastUpdateTime, NULL);
- pthread_cond_broadcast(&g_condUPnPControlURL);
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "Got Device Description\n");
-
- // find router info
- FindRouterInfo(inBuffer, iLen);
-
- if (FindEventURL(inBuffer, iLen, szEventURL) != 0) {
- szEventURL[0] = '\0';
- }
- else {
- ParseURL(szEventURL,
- g_szRouterHostPortEvent, sizeof(g_szRouterHostPortEvent), &g_saddrRouterEvent, g_szEventURL, sizeof(g_szEventURL));
- if ((strlen(g_szRouterHostPortEvent) == 0) ||
- (g_saddrRouterEvent.sin_addr.s_addr == INADDR_NONE)) {
- memcpy(&g_saddrRouterEvent, &g_saddrRouterBase,
- sizeof(g_saddrRouterEvent));
- strlcpy(g_szRouterHostPortEvent, g_szRouterHostPortBase, sizeof(g_szRouterHostPortEvent));
- }
-
- EventInit();
- }
-
- pthread_mutex_unlock(&g_xUPnP);
-
-cleanup:
- if (outBuffer != NULL) free(outBuffer);
- if (inBuffer != NULL) free(inBuffer);
-}
-
-
-static void GetIPByName(char *hostname, unsigned long *ip_ret)
-{
- unsigned long ip;
-
- ip = inet_addr(hostname);
- if (ip == INADDR_NONE) {
- struct hostent *pHEnt;
- pHEnt = gethostbyname(hostname);
- if (pHEnt == NULL) {
- if (g_fLogging & NALOG_ALERT)
- fprintf(g_log, "Can't translate [%s] to IP...\n", hostname);
- g_dwLocalIP = INADDR_ANY;
- return;
- }
- ip = *(unsigned long *)(pHEnt->h_addr);
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "hostname [%s] to ip: %u.%u.%u.%u\n", hostname,
- ((uint8_t*)&ip)[0], ((uint8_t*)&ip)[1], ((uint8_t*)&ip)[2], ((uint8_t*)&ip)[3]);
- }
- *ip_ret = ip;
-}
-
-static void SetLocalIP()
-{
- PIPINFO pIPInfo = NULL;
- int count = GetIPInfo(&pIPInfo);
- if (NULL != pIPInfo)
- {
- // choose first non IPV6 address
- // iterate through array and set port information
- int i;
- unsigned long dwFirst = 0;
- for(i = 0; i < count; i++)
+ if (ptr == mDNSNULL || ptr == end) return; // not a message we care about
+
+ // find "http://", starting from where we left off
+ while (ptr && ptr != end)
{
- if (!(pIPInfo[i].iFlags & ISIPV6) &&
- (strncmp(pIPInfo[i].szIfName, "ppp", 3) != 0))
+ if (*ptr == 'h' && (strncasecmp(ptr, "http://", 7) == 0)) // find the first 'h'; is this a URL? if not, keep looking
{
- unsigned long dwTemp;
-
- memcpy(&dwTemp, pIPInfo[i].abIP, sizeof(unsigned long));
-
- if (0 != GetNATIPNetmask(dwTemp)) {
- g_dwLocalIP = dwTemp;
- break;
- }
-
- if (0 == dwFirst)
- dwFirst = dwTemp;
+ int i;
+ char *addrPtr = mDNSNULL;
+
+ ptr += 7; //skip over "http://"
+ if (ptr >= end) { LogOperation("LNT_ConfigureRouterInfo: past end of buffer and no URL!"); return; }
+ addrPtr = ptr;
+ for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break; // first find the beginning of the URL and count the chars
+ if (addrPtr == mDNSNULL || addrPtr == end) return; // not a valid message
+
+ // allocate the buffer (len i+1 so we have space to terminate the string)
+ if (m->UPnPRouterAddressString != mDNSNULL) mDNSPlatformMemFree(m->UPnPRouterAddressString);
+ if ((m->UPnPRouterAddressString = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate router address string"); return; }
+
+ strncpy((char *)m->UPnPRouterAddressString, ptr, i); // copy the address string
+ m->UPnPRouterAddressString[i] = '\0'; // terminate the string
+ LogOperation("LNT_ConfigureRouterInfo: router address string [%s]", m->UPnPRouterAddressString);
+ break;
}
+ ptr++; // continue
}
- if (i == count)
- g_dwLocalIP = dwFirst;
- FreeIPInfo(pIPInfo);
- }
-
-}
-
-static int FindTagContent(const char *text, const char *tagname, char *buf)
-{
- char *p;
- // parse the xml
- p = strstr(text, tagname);
- if (p == NULL) {
- if (g_fLogging & NALOG_INFO0)
- fprintf(g_log, "FindTagContent: can't find %s\n", tagname);
- return NA_E_PARSE_ERROR;
- }
-
- if (sscanf(p, "%*[^>]> %[^ <] <", buf) < 1) {
- if (g_fLogging & NALOG_INFO0)
- fprintf(g_log, "FindTagContent: Can't parse tag %s\n", tagname);
- return NA_E_PARSE_ERROR;
- }
-
- return NA_E_SUCCESS;
-}
-
-mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp)
-{
- //int iLen;
- char szEPort[10];
- //char szRemoteHost[1024];
- //unsigned long dwIP;
- Property propArgs[3];
- PHTTPResponse resp;
- int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP;
- snprintf(szEPort, sizeof(szEPort), "%u", mDNSVal16(PubPort));
-
- bzero(propArgs, sizeof(propArgs));
- propArgs[0].pszName = "NewRemoteHost";
- propArgs[0].pszValue = "";
- propArgs[0].pszType = "string";
- propArgs[1].pszName = "NewExternalPort";
- propArgs[1].pszValue = szEPort;
- propArgs[1].pszType = "ui2";
- propArgs[2].pszName = "NewProtocol";
- if (protocol == IPPROTO_TCP) {
- propArgs[2].pszValue = "TCP";
- }
- else if (protocol == IPPROTO_UDP) {
- propArgs[2].pszValue = "UDP";
- }
- else {
- return -1;
- }
- propArgs[2].pszType = "string";
-
- resp = SendSOAPMsgControlAction(
- "DeletePortMapping", 3, propArgs, FALSE);
- if (resp == NULL) {
- return mStatus_NATTraversal;
- }
-
- if (strcmp(resp->pszStatus, "200") != 0) {
- DeleteHTTPResponse(resp);
- return mStatus_NATTraversal;
- }
-
- DeleteHTTPResponse(resp);
- return mStatus_NoError;
-}
-
-
-static int GetMappingUnused(unsigned short eport, int protocol);
-
-extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp)
-{
- char szEPort[6];
- char szIPort[6];
- unsigned long dwIP;
- char szLocalIP[30];
- char descr[40];
- Property propArgs[8];
- PHTTPResponse resp;
- int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP;
-
- if (NA_E_EXISTS == GetMappingUnused(mDNSVal16(pub), protocol))
- return mStatus_AlreadyRegistered;
-
- //DeletePortMapping(eport, protocol);
-
- snprintf(szEPort, sizeof(szEPort), "%u", mDNSVal16(pub));
- snprintf(szIPort, sizeof(szIPort), "%u", mDNSVal16(priv));
-
- dwIP = g_dwLocalIP;
- snprintf(szLocalIP, sizeof(szLocalIP), "%u.%u.%u.%u",
- ((uint8_t*)&dwIP)[0], ((uint8_t*)&dwIP)[1], ((uint8_t*)&dwIP)[2], ((uint8_t*)&dwIP)[3]);
-
- bzero(propArgs, sizeof(propArgs));
- propArgs[0].pszName = "NewRemoteHost";
- propArgs[0].pszValue = "";
- propArgs[0].pszType = "string";
- propArgs[1].pszName = "NewExternalPort";
- propArgs[1].pszValue = szEPort;
- propArgs[1].pszType = "ui2";
- propArgs[2].pszName = "NewProtocol";
- if (protocol == IPPROTO_TCP) {
- propArgs[2].pszValue = "TCP";
- }
- else if (protocol == IPPROTO_UDP) {
- propArgs[2].pszValue = "UDP";
- }
- else {
- return mStatus_BadParamErr;
- }
- propArgs[2].pszType = "string";
- propArgs[3].pszName = "NewInternalPort";
- propArgs[3].pszValue = szIPort;
- propArgs[3].pszType = "ui2";
- propArgs[4].pszName = "NewInternalClient";
- propArgs[4].pszValue = szLocalIP;
- propArgs[4].pszType = "string";
- propArgs[5].pszName = "NewEnabled";
- propArgs[5].pszValue = "1";
- propArgs[5].pszType = "boolean";
- propArgs[6].pszName = "NewPortMappingDescription";
- snprintf(descr, sizeof(descr), "iC%u", mDNSVal16(pub));
- //propArgs[6].pszValue = "V";
- propArgs[6].pszValue = descr;
- propArgs[6].pszType = "string";
- propArgs[7].pszName = "NewLeaseDuration";
- propArgs[7].pszValue = "0";
- propArgs[7].pszType = "ui4";
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "Sending AddPortMapping priv %u pub %u\n", mDNSVal16(priv), mDNSVal16(pub));
-
- resp = SendSOAPMsgControlAction(
- "AddPortMapping", 8, propArgs, FALSE);
-
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "AddPortMapping resp %p\n", resp);
-
- if (resp == NULL) {
- return mStatus_NATTraversal;
- }
-
- if (strcmp(resp->pszStatus, "200") != 0) {
- DeleteHTTPResponse(resp);
- return mStatus_NATTraversal;
- }
-
- DeleteHTTPResponse(resp);
- return mStatus_NoError;
-}
-
-static int GetMappingUnused(unsigned short eport, int protocol)
-{
- char buf[1024];
- char szPort[10];
- Property propArgs[3];
- PHTTPResponse resp;
- unsigned long ip = 0;
-
- snprintf(szPort, sizeof(szPort), "%u", eport);
-
- bzero(&propArgs, sizeof(propArgs));
- propArgs[0].pszName = "NewRemoteHost";
- propArgs[0].pszValue = "";
- propArgs[0].pszType = "string";
- propArgs[1].pszName = "NewExternalPort";
- propArgs[1].pszValue = szPort;
- propArgs[1].pszType = "ui2";
- propArgs[2].pszName = "NewProtocol";
- if (protocol == IPPROTO_TCP) {
- propArgs[2].pszValue = "TCP";
- }
- else if (protocol == IPPROTO_UDP) {
- propArgs[2].pszValue = "UDP";
- }
- else {
- return NA_E_INVALID_PARAMETER;
- }
- propArgs[2].pszType = "string";
- resp = SendSOAPMsgControlAction(
- "GetSpecificPortMappingEntry", 3, propArgs, FALSE);
- if (resp != NULL) {
- if ((strcmp(resp->pszStatus, "200") == 0) &&
- (FindTagContent(resp->pszBody, "NewInternalClient", buf) == 0))
+ // find port and router URL, starting after the "http://" if it was there
+ while (ptr && ptr != end)
{
- GetIPByName(buf, &ip);
- if (ip == g_dwLocalIP) {
- // (perhaps we let it go?)
- DeleteHTTPResponse(resp);
- return NA_E_SUCCESS;
+ if (*ptr == ':') // found the port number
+ {
+ int port;
+ ptr++; // skip over ':'
+ if (ptr == end) { LogOperation("LNT_ConfigureRouterInfo: reached end of buffer and no address!"); return; }
+ port = (int)strtol(ptr, (char **)mDNSNULL, 10); // get the port
+ m->UPnPRouterPort = mDNSOpaque16fromIntVal(port); // store it properly converted
}
- else {
- DeleteHTTPResponse(resp);
- return NA_E_EXISTS;
+ else if (*ptr == '/') // found router URL
+ {
+ int j;
+ char *urlPtr;
+ m->UPnPInterfaceID = InterfaceID;
+ if (mDNSIPPortIsZero(m->UPnPRouterPort)) m->UPnPRouterPort = mDNSOpaque16fromIntVal(80); // fill in default port if we didn't find one before
+
+ urlPtr = ptr;
+ for (j = 0; urlPtr && urlPtr != end; j++, urlPtr++) if (*urlPtr == '\r') break; // first find the end of the line and count the chars
+ if (urlPtr == mDNSNULL || urlPtr == end) return; // not a valid message
+
+ // allocate the buffer (len j+1 so we have space to terminate the string)
+ if (m->UPnPRouterURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPRouterURL);
+ if ((m->UPnPRouterURL = (mDNSu8 *) mDNSPlatformMemAllocate(j+1)) == mDNSNULL) { LogMsg("can't allocate router URL"); return; }
+
+ // now copy everything to the end of the line
+ strncpy((char *)m->UPnPRouterURL, ptr, j); // this URL looks something like "/dyndev/uuid:0013-108c-4b3f0000f3dc"
+ m->UPnPRouterURL[j] = '\0'; // terminate the string
+ break; // we've got everything we need, so get out here
}
+ ptr++; // continue
}
- DeleteHTTPResponse(resp);
- }
-
- return NA_E_SUCCESS;
-}
-
-mStatus LNT_GetPublicIP(mDNSv4Addr *IpPtr)
-{
- char buf[1024];
- PHTTPResponse resp;
- static struct timeval tvLastGoodIP = {0,0};
- static unsigned long dwLastGoodIP;
- struct timeval tv;
- unsigned long *ip = (unsigned long *)IpPtr;
- if (ip == NULL) return mStatus_BadParamErr;
-
- gettimeofday(&tv, NULL);
- GetTimeElapsed(&tvLastGoodIP, &tv, &tv);
- if (tv.tv_sec < 4)
- {
- return dwLastGoodIP;
- }
-
- resp = SendSOAPMsgControlAction(
- "GetExternalIPAddress", 0, NULL, FALSE);
-
- if (resp == NULL)
- return mStatus_NATTraversal;
-
- if (FindTagContent(resp->pszBody, "NewExternalIPAddress", buf) == 0) {
- if (g_fLogging & NALOG_INFO1)
- fprintf(g_log, "Mapped remote host = %s\n", buf);
- *ip = inet_addr(buf);
- DeleteHTTPResponse(resp);
- gettimeofday(&tvLastGoodIP, NULL);
- dwLastGoodIP = *ip;
+ if (ptr == mDNSNULL || ptr == end) return; // not a valid message
+ LogOperation("Router port %d, URL set to [%s]...", mDNSVal16(m->UPnPRouterPort), m->UPnPRouterURL);
- return mStatus_NoError;
+ // now send message to get the device description
+ GetDeviceDescription(m, &m->tcpDeviceInfo);
}
- DeleteHTTPResponse(resp);
- return mStatus_NATTraversal;
-}
-
-static void SendDiscoveryMsg()
-{
- // do it twice to avoid lost packet
- //SendUDPMsg(szSSDPMsgDiscoverNAT);
- SendUDPMsg(szSSDPMsgDiscoverRoot);
- SendUDPMsg(szSSDPMsgDiscoverIGD);
- SendUDPMsg(szSSDPMsgDiscoverNAT);
-}
-
-// Set up threads for upnp responses, etc.
-int LegacyNATInit(void)
-{
- //pthread_t UDPthread;
- pthread_attr_t attr;
- int iRet;
- //struct timeval tv;
- LogOperation("LegacyNATInit");
-
- static int fFirstInitLocks = TRUE;
- FILE *log = NULL;
-
- g_fLogging = 0;
- //g_fLogging = ~0; // Turns ALL logging on
- g_log = stderr;
-
- SetLocalIP();
-
- g_fQuit = FALSE;
-
- if (fFirstInitLocks)
+mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
{
- // init locks
- if (pthread_mutex_init(&g_xUPnP, NULL)) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(log, "UpnpInit - mutex init failed\n");
- return NA_E_INTERNAL_ERROR;
- }
- if (pthread_cond_init(&g_condUPnP, NULL)) {
- pthread_mutex_destroy(&g_xUPnP);
- if (g_fLogging & NALOG_ERROR)
- fprintf(log, "UpnpInit - cond init failed\n");
- return NA_E_INTERNAL_ERROR;
- }
- if (pthread_cond_init(&g_condUPnPControlURL, NULL)) {
- pthread_mutex_destroy(&g_xUPnP);
- pthread_cond_destroy(&g_condUPnP);
- if (g_fLogging & NALOG_ERROR)
- fprintf(log, "UpnpInit - cond init failed\n");
- return NA_E_INTERNAL_ERROR;
- }
- if (pthread_mutex_init(&g_xUPnPMsg, NULL)) {
- pthread_mutex_destroy(&g_xUPnP);
- pthread_cond_destroy(&g_condUPnP);
- pthread_cond_destroy(&g_condUPnPControlURL);
- if (g_fLogging & NALOG_ERROR)
- fprintf(log, "UpnpInit - mutex init failed\n");
- return NA_E_INTERNAL_ERROR;
- }
-
- fFirstInitLocks = FALSE;
- }
-
- if (g_fFirstInit)
- {
- // initialize UDP socket for SSDP
- g_sUDP = SSDPListen();
- g_sUDPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // sock to signal canccelation to UDP thread
- if (g_sUDP < 0 || g_sUDPCancel < 0) {
- if (g_fLogging & NALOG_ERROR)
- fprintf(log, "UpnpInit - Failed to init multicast socket.\n");
- return NA_E_INTERNAL_ERROR;
- }
-
- // make UDP thread
- pthread_attr_init(&attr);
- iRet = pthread_create(&g_UDPthread, &attr, UDPProc, log);
- if (iRet != 0) {
- g_fFirstInit = TRUE; // so we'll redo this part next time
- close(g_sUDP);
- g_sUDP = -1;
- if (g_fLogging & NALOG_ERROR)
- fprintf(log, "UpnpInit - pthread create failed (%d)\n", iRet);
- return NA_E_THREAD_ERROR;
- }
-
- // set this to FALSE only if first call succeeded
- g_fFirstInit = FALSE;
+ static const mDNSu8 msg[] =
+ "M-SEARCH * HTTP/1.1\r\n"
+ "Host:239.255.255.250:1900\r\n"
+ "ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n"
+ "Man:\"ssdp:discover\"\r\n"
+ "MX:3\r\n\r\n";
- //TracePrint(ELL_TRACE, "UPnP init passed\n");
+ LogOperation("LNT_SendDiscoveryMsg %.4a %.4a", &m->Router.ip.v4, &m->ExternalAddress);
- //tv.tv_sec = 0;
- //tv.tv_usec = 20000; // wait 20ms for thread/udp/multicast init
- //select(0, 0, 0, 0, &tv);
+ if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSIPv4AddressIsZero(m->ExternalAddress))
+ mDNSPlatformSendUDP(m, msg, msg + sizeof(msg), 0, &m->Router, SSDPPort);
}
- // send discovery message
- SendDiscoveryMsg();
-
- return NA_E_SUCCESS;
-}
-
-int LegacyNATDestroy()
-{
- void *UDPThreadRetVal;
- g_fQuit = TRUE;
- if (g_sTCPCancel >= 0) close(g_sTCPCancel);
- if (g_sUDPCancel >= 0) close(g_sUDPCancel);
- pthread_join(g_UDPthread, &UDPThreadRetVal);
- g_sTCPCancel = -1;
- g_sUDPCancel = -1;
- g_fFirstInit = TRUE;
- g_fUPnPEnabled = FALSE;
- g_fControlURLSet = FALSE;
- return NA_E_SUCCESS;
-}
+#endif /* _LEGACY_NAT_TRAVERSAL_ */
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
+
$Log: ConfigurationRights.h,v $
+Revision 1.2 2006/08/14 23:15:47 cheshire
+Tidy up Change History comment
+
Revision 1.1 2005/02/05 01:59:19 cheshire
Add Preference Pane to facilitate testing of DDNS & wide-area features
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
+
$Log: DNSServiceDiscoveryPref.h,v $
+Revision 1.6 2006/08/14 23:15:47 cheshire
+Tidy up Change History comment
+
Revision 1.5 2005/02/26 00:44:24 cheshire
Restore default reg domain if user deletes text and clicks "apply"
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
+
$Log: DNSServiceDiscoveryPref.m,v $
+Revision 1.10 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.9 2007/02/09 00:39:06 cheshire
+Fix compile warnings
+
+Revision 1.8 2006/08/14 23:15:47 cheshire
+Tidy up Change History comment
+
+Revision 1.7 2006/07/14 03:59:14 cheshire
+Fix compile warnings: 'sortUsingFunction:context:' comparison function needs to return int
+
Revision 1.6 2005/02/26 00:44:24 cheshire
Restore default reg domain if user deletes text and clicks "apply"
@implementation DNSServiceDiscoveryPref
-static CFComparisonResult
+static int
MyArrayCompareFunction(id val1, id val2, void *context)
{
+ (void)context; // Unused
return CFStringCompare((CFStringRef)val1, (CFStringRef)val2, kCFCompareCaseInsensitive);
}
-static CFComparisonResult
+static int
MyDomainArrayCompareFunction(id val1, id val2, void *context)
{
+ (void)context; // Unused
NSString *domain1 = [val1 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
NSString *domain2 = [val2 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
return CFStringCompare((CFStringRef)domain1, (CFStringRef)domain2, kCFCompareCaseInsensitive);
static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
+ (void)store; // Unused
+ (void)changedKeys; // Unused
DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
assert(me != NULL);
static void ServiceDomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *replyDomain, void *context, DNSServiceFlags enumType)
{
+ (void)sdRef; // Unused
+ (void)interfaceIndex; // Unused
+ (void)errorCode; // Unused
if (strcmp(replyDomain, "local.") == 0) return; // local domain is not interesting
DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
}
-void
+static void
browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *replyDomain, void *context)
{
}
-void
+static void
registrationDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *replyDomain, void *context)
{
-void
+static void
MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
{
CFSocketNativeHandle sock;
if ([defaultBrowseDomainsArray count] > 0) {
NSEnumerator * arrayEnumerator = [defaultBrowseDomainsArray objectEnumerator];
- while (domain = [arrayEnumerator nextObject]) {
+ while ((domain = [arrayEnumerator nextObject]) != NULL) {
if ([self domainAlreadyInList:domain] == NO) break;
}
}
- (IBAction)removeBrowseDomainClicked:(id)sender;
{
+ (void)sender; // Unused
int selectedBrowseDomain = [browseDomainList selectedRow];
[browseDomainsArray removeObjectAtIndex:selectedBrowseDomain];
[browseDomainList reloadData];
- (int)numberOfRowsInTableView:(NSTableView *)tableView;
{
+ (void)tableView; // Unused
int numberOfRows = 0;
if (browseDomainsArray) {
}
-- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem;
+- (void)tabView:(NSTabView *)xtabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem;
{
+ (void)xtabView; // Unused
+ (void)tabViewItem; // Unused
[browseDomainList deselectAll:self];
[mainWindow makeFirstResponder:nil];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row;
{
+ (void)tableView; // Unused
NSDictionary *browseDomainDict;
id value = nil;
NSDictionary *domainDict;
NSString *domainName;
NSEnumerator *arrayEnumerator = [browseDomainsArray objectEnumerator];
- while (domainDict = [arrayEnumerator nextObject]) {
+ while ((domainDict = [arrayEnumerator nextObject]) != NULL) {
domainName = [domainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return YES;
}
- (void)addBrowseDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
+ (void)contextInfo; // Unused
[sheet orderOut:self];
[self enableControls];
if ([sender isEqualTo:hostNameSharedSecretButton]) {
if (hostNameSharedSecretValue) {
[sharedSecretValue setStringValue:hostNameSharedSecretValue];
- } else if (keyName = [self sharedSecretKeyName:[hostName stringValue]]) {
+ } else if ((keyName = [self sharedSecretKeyName:[hostName stringValue]]) != NULL) {
[sharedSecretName setStringValue:keyName];
[sharedSecretValue setStringValue:@"****************"];
} else {
} else {
if (regSharedSecretValue) {
[sharedSecretValue setStringValue:regSharedSecretValue];
- } else if (keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) {
+ } else if ((keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) != NULL) {
[sharedSecretName setStringValue:keyName];
[sharedSecretValue setStringValue:@"****************"];
} else {
- (void)controlTextDidChange:(NSNotification *)notification;
{
+ (void)notification; // Unused
[self updateApplyButtonState];
}
- (IBAction)comboAction:(id)sender;
{
+ (void)sender; // Unused
[self updateApplyButtonState];
}
- (IBAction)applyClicked:(id)sender
{
+ (void)sender; // Unused
[self applyCurrentState];
}
- (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
+ (void)sheet; // Unused
DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)contextInfo;
if (returnCode == NSAlertDefaultReturn) {
SecKeychainAttributeInfo attrInfo;
SecKeychainAttributeList *attrList = NULL;
SecKeychainAttribute attribute;
- int i;
+ unsigned int i;
tags[0] = kSecAccountItemAttr;
attrInfo.count = 1;
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
{
+ (void)row; // Unused
+ (void)tableView; // Unused
return browseDomainListEnabled;
}
- (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view
{
+ (void)view; // Unused
[self enableControls];
}
- (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view
{
+ (void)view; // Unused
[self disableControls];
}
+@end
+
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
-@end
\ No newline at end of file
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>Bonjour</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string>BonjourPref</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.preference.bonjour</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string></string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSMainNibFile</key>
+ <string>DNSServiceDiscoveryPref</string>
+ <key>NSPrefPaneIconFile</key>
+ <string>BonjourPref.tiff</string>
+ <key>NSPrefPaneIconLabel</key>
+ <string>Bonjour</string>
+ <key>NSPrincipalClass</key>
+ <string>DNSServiceDiscoveryPref</string>
+</dict>
+</plist>
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
+
$Log: PrivilegedOperations.c,v $
+Revision 1.7 2007/02/09 00:39:06 cheshire
+Fix compile warnings
+
+Revision 1.6 2006/08/14 23:15:47 cheshire
+Tidy up Change History comment
+
+Revision 1.5 2006/06/10 02:07:11 mkrochma
+Whoa. Make sure code compiles before checking it in.
+
+Revision 1.4 2006/05/27 02:32:38 mkrochma
+Wait for installer script to exit before returning result
+
Revision 1.3 2005/06/04 04:50:00 cheshire
<rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
Use installtool instead of requiring ddnswriteconfig to self-install
Boolean gToolApproved = false;
-pid_t execTool(const char *args[])
+static pid_t execTool(const char *args[])
// fork/exec and return new pid
{
pid_t child;
{
char *installerargs[] = { toolSourcePath, NULL };
err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL);
- if (err == noErr)
- gToolApproved = true;
+ if (err == noErr) {
+ int status;
+ int pid = wait(&status);
+ if (pid > 0 && WIFEXITED(status)) {
+ err = WEXITSTATUS(status);
+ if (err == noErr) {
+ gToolApproved = true;
+ }
+ } else {
+ err = -1;
+ }
+ }
(void) AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
}
}
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
+
$Log: PrivilegedOperations.h,v $
+Revision 1.5 2006/08/14 23:15:47 cheshire
+Tidy up Change History comment
+
Revision 1.4 2005/06/04 04:50:00 cheshire
<rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
Use installtool instead of requiring ddnswriteconfig to self-install
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
+
$Log: ddnswriteconfig.m,v $
+Revision 1.9 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.8 2007/07/20 23:41:03 mkrochma
+<rdar://problem/5348663> null deref in ddnswriteconfig
+
+Revision 1.7 2007/03/07 00:49:00 cheshire
+<rdar://problem/4618207> Security: ddnswriteconfig does not verify that authorization blob is of correct size
+
+Revision 1.6 2007/02/09 00:39:06 cheshire
+Fix compile warnings
+
+Revision 1.5 2006/08/14 23:15:47 cheshire
+Tidy up Change History comment
+
Revision 1.4 2005/06/04 04:47:47 cheshire
<rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
Remove self-installing capability of ddnswriteconfig
static AuthorizationRef gAuthRef = 0;
-OSStatus
+static OSStatus
WriteArrayToDynDNS(CFStringRef arrayKey, CFArrayRef domainArray)
{
SCPreferencesRef store;
readTaggedBlock(int fd, u_int32_t *pTag, u_int32_t *pLen, char **ppBuff)
// Read tag, block len and block data from stream and return. Dealloc *ppBuff via free().
{
- ssize_t num;
- u_int32_t tag, len;
+ ssize_t num, len;
+ u_int32_t tag;
int result = 0;
num = read(fd, &tag, sizeof tag);
-int
+static int
SetAuthInfo( int fd)
{
int result = 0;
result = readTaggedBlock( fd, &tag, &len, &p);
require( result == 0, ReadParamsFailed);
+ require( len == sizeof(AuthorizationExternalForm), ReadParamsFailed);
+ require( len == kAuthorizationExternalFormLength, ReadParamsFailed);
if (gAuthRef != 0) {
(void) AuthorizationFree(gAuthRef, kAuthorizationFlagDestroyRights);
}
-int
+static int
HandleWriteDomain(int fd, int domainType)
{
CFArrayRef domainArray;
}
-int
+static int
HandleWriteHostname(int fd)
{
CFArrayRef domainArray;
}
-SecAccessRef
+static SecAccessRef
MyMakeUidAccess(uid_t uid)
{
// make the "uid/gid" ACL subject
uid, // uid to match
0 // gid (not matched here)
};
- CSSM_LIST_ELEMENT subject2 = { NULL, 0 };
+ CSSM_LIST_ELEMENT subject2 = { NULL, 0, 0, {{0,0,0}} };
subject2.Element.Word.Data = (UInt8 *)&selector;
subject2.Element.Word.Length = sizeof(selector);
- CSSM_LIST_ELEMENT subject1 = { &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID };
+ CSSM_LIST_ELEMENT subject1 = { &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID, {{0,0,0}} };
// rights granted (replace with individual list if desired)
false
};
// ACL entries (any number, just one here)
- CSSM_ACL_ENTRY_INFO acls[] = {
+ CSSM_ACL_ENTRY_INFO acls =
{
- // prototype
+ // CSSM_ACL_ENTRY_PROTOTYPE
{
- // TypedSubject
- { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
- false, // Delegate
- // rights for this entry
- { sizeof(rights) / sizeof(rights[0]), rights },
- // rest is defaulted
- }
- }
- };
+ { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, // TypedSubject
+ false, // Delegate
+ { sizeof(rights) / sizeof(rights[0]), rights }, // Authorization rights for this entry
+ { { 0, 0 }, { 0, 0 } }, // CSSM_ACL_VALIDITY_PERIOD
+ "" // CSSM_STRING EntryTag
+ },
+ // CSSM_ACL_HANDLE
+ 0
+ };
SecAccessRef access = NULL;
- (void) SecAccessCreateFromOwnerAndACL(&owner, sizeof(acls) / sizeof(acls[0]), acls, &access);
+ (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &access);
return access;
}
-OSStatus
+static OSStatus
MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 serviceNameLength, const char *serviceName,
UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData)
{
}
-int
+static int
SetKeychainEntry(int fd)
// Create a new entry in system keychain, or replace existing
{
if ( argc == 3 && 0 == strcmp( argv[2], "V"))
return PRIV_OP_TOOL_VERS;
- if ( argc >= 1)
+ if ( argc > 1)
{
commFD = strtol( argv[1], NULL, 0);
lseek( commFD, 0, SEEK_SET);
[pool release];
return result;
}
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) ddnswriteconfig " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
#!/usr/bin/perl
+# Emacs settings: -*- tab-width: 4 -*-
#
# File: installtool
#
# Change History (most recent first):
#
# $Log: installtool,v $
+# Revision 1.3 2006/09/05 20:00:13 cheshire
+# Moved Emacs settings to second line of file
+#
+# Revision 1.2 2006/08/14 23:15:14 cheshire
+# Added "tab-width" emacs header line
+#
# Revision 1.1 2005/06/04 04:51:48 cheshire
# <rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
# Added separate "installtool" script instead of making ddnswriteconfig self-install
--- /dev/null
+On Mac OS X, mDNSResponder now runs with user-ID and group-ID
+"_mdnsresponder". In order to perform certain privileged operations, a
+helper (unimagintively called mDNSResponderHelper) runs as root when
+needed and handles requests from mDNSResponder.
+
+
+* A new LaunchD job com.apple.mDNSResponderHelper starts
+ mDNSResponderHelper on demand. The helper exits after approximately
+ 10 seconds of idle time.
+
+* The com.apple.mDNSResponder LaunchD job specifies the account under
+ which to run, so that mDNSResponder starts as _mdnsresponder. When
+ run as root--- e.g. from the command line with `sudo'---
+ mDNSResponder drops privileges itself.
+
+* A subdirectory named "mdns" and owned by _mdnsresponder has been
+ created in /var/run. The PID file and uDNS server socket has been
+ moved to that subdirectory.
+
+* There are currently six remote procedure calls handled by
+ mDNSResponderHelper: mDNSDynamicStoreSetConfig,
+ mDNSPreferencesSetName, mDNSKeychainGetSecrets,
+ mDNSAutoTunnelInterfaceUpDown, mDNSConfigureServer, and
+ mDNSAutoTunnelSetKeys
+
+* mDNSDynamicStoreSetConfig allows mDNSResponder to set the
+ MulticastDNS, PrivateDNS, or DynamicDNS configurations.
+
+* mDNSPreferencesSetName allows mDNSResponder to set the computer name
+ or local host name, and displays a notification if there was a
+ conflict.
+
+* mDNSKeychainGetSecrets causes mDNSResponderHelper to collect DNS
+ keys from the system keychain. SetDomainSecrets uses the result to
+ populate AuthInfoList. One could refactor this code further so that
+ mDNSResponderHelper performs all the cryptographic operations, with
+ the result that a compromise of mDNSResponder does not compromise
+ keys. But I think that may be more change than is advisable at this
+ point.
+
+* On the advice of the Security.framework team, I've used
+ SecKeychainSetPreferenceDomain to ensure that the system keychain is
+ references whenever a NULL SecKeychainRef is used. Wherever a
+ SecKeychainRef is needed, NULL is now specified.
+
+* mDNSAutoTunnelInterfaceUpDown, mDNSConfigureServer, and
+ mDNSAutoTunnelSetKeys do various setup and teardown for BTMM.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*
* Formatting notes:
* This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
* understand why variable y is not of type "char*" just proves the point that poor code
* layout leads people to unfortunate misunderstandings about how the C language really works.)
- Change History (most recent first):
+ Change History (most recent first):
$Log: SamplemDNSClient.c,v $
-Revision 1.47 2006/01/10 02:29:22 cheshire
-<rdar://problem/4403861> Cosmetic IPv6 address display problem in mDNS test tool
-
-Revision 1.46 2004/11/02 01:32:34 cheshire
-<rdar://problem/3861705> Update code so it still compiles when DNSServiceDiscovery.h is deprecated
-
-Revision 1.45 2004/06/15 02:39:47 cheshire
-When displaying error message, only show command name, not entire path
-
-Revision 1.44 2004/05/28 02:20:06 cheshire
-If we allow dot or empty string for domain when resolving a service,
-it should be a synonym for "local"
-
-Revision 1.43 2004/02/03 22:07:50 cheshire
-<rdar://problem/3548184>: Widen columns to display non-local domains better
+Revision 1.53 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-Revision 1.42 2003/12/03 11:39:17 cheshire
-<rdar://problem/3468977> Browse output misaligned in mDNS command-line tool
-(Also fix it to add leading space when the hours part of the time is only one digit)
+Revision 1.52 2007/03/06 22:45:52 cheshire
-Revision 1.41 2003/10/30 22:52:57 cheshire
-<rdar://problem/3468977> Browse output misaligned in mDNS command-line tool
+<rdar://problem/4138615> argv buffer overflow issues
-Revision 1.40 2003/09/26 01:07:06 cheshire
-Added test case to test fix for <rdar://problem/3427923>
+Revision 1.51 2007/02/13 18:56:45 cheshire
+<rdar://problem/4993485> Mach mDNS tool inconsistent with UDS-based dns-sd tool
+(missing domain should mean "system default(s)", not "local")
-Revision 1.39 2003/08/18 19:05:45 cheshire
-<rdar://problem/3382423> UpdateRecord not working right
-Added "newrdlength" field to hold new length of updated rdata
+Revision 1.50 2007/01/05 08:30:47 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.38 2003/08/12 19:56:25 cheshire
-Update to APSL 2.0
+Revision 1.49 2007/01/04 21:54:49 cheshire
+Fix compile warnings related to the deprecated Mach-based API
-Revision 1.37 2003/08/05 20:39:25 cheshire
-<rdar://problem/3362184> mDNS buffered std out makes it impossible to use from another tool
-Added "setlinebuf(stdout);"
+Revision 1.48 2006/08/14 23:24:39 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.36 2003/07/19 03:23:13 cheshire
-<rdar://problem/2986147> mDNSResponder needs to receive and cache larger records
-
-Revision 1.35 2003/07/11 01:57:18 cheshire
-Add checkin history header
+Revision 1.47 2006/01/10 02:29:22 cheshire
+<rdar://problem/4403861> Cosmetic IPv6 address display problem in mDNS test tool
- */
+*/
#include <libc.h>
#define BIND_8_COMPAT
#include <AvailabilityMacros.h>
#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+
#include <DNSServiceDiscovery/DNSServiceDiscovery.h>
//*************************************************************************************************************
static void MyHandleMachMessage(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
- (void)port; // Unused
- (void)size; // Unused
- (void)info; // Unused
+ (void)port; // Unused
+ (void)size; // Unused
+ (void)info; // Unused
DNSServiceDiscovery_handleReply(msg);
}
static int AddDNSServiceClientToRunLoop(dns_service_discovery_ref client)
- {
+ {
mach_port_t port = DNSServiceDiscoveryMachPort(client);
- if (!port)
- return(-1);
- else
- {
- CFMachPortContext context = { 0, 0, NULL, NULL, NULL };
- Boolean shouldFreeInfo;
- CFMachPortRef cfMachPort = CFMachPortCreateWithPort(kCFAllocatorDefault, port, MyHandleMachMessage, &context, &shouldFreeInfo);
- CFRunLoopSourceRef rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
- CFRelease(rls);
- return(0);
- }
- }
+ if (!port)
+ return(-1);
+ else
+ {
+ CFMachPortContext context = { 0, 0, NULL, NULL, NULL };
+ Boolean shouldFreeInfo;
+ CFMachPortRef cfMachPort = CFMachPortCreateWithPort(kCFAllocatorDefault, port, MyHandleMachMessage, &context, &shouldFreeInfo);
+ CFRunLoopSourceRef rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+ CFRelease(rls);
+ return(0);
+ }
+ }
//*************************************************************************************************************
// Sample callback functions for each of the operation types
}
#define DomainMsg(X) ((X) == DNSServiceDomainEnumerationReplyAddDomain ? "Added" : \
- (X) == DNSServiceDomainEnumerationReplyAddDomainDefault ? "(Default)" : \
- (X) == DNSServiceDomainEnumerationReplyRemoveDomain ? "Removed" : "Unknown")
+ (X) == DNSServiceDomainEnumerationReplyAddDomainDefault ? "(Default)" : \
+ (X) == DNSServiceDomainEnumerationReplyRemoveDomain ? "Removed" : "Unknown")
static void regdom_reply(DNSServiceDomainEnumerationReplyResultType resultType, const char *replyDomain,
- DNSServiceDiscoveryReplyFlags flags, void *context)
+ DNSServiceDiscoveryReplyFlags flags, void *context)
{
- (void)context; // Unused
+ (void)context; // Unused
printtimestamp();
printf("Recommended Registration Domain %s %s", replyDomain, DomainMsg(resultType));
if (flags) printf(" Flags: %X", flags);
}
static void browsedom_reply(DNSServiceDomainEnumerationReplyResultType resultType, const char *replyDomain,
- DNSServiceDiscoveryReplyFlags flags, void *context)
+ DNSServiceDiscoveryReplyFlags flags, void *context)
{
- (void)context; // Unused
+ (void)context; // Unused
printtimestamp();
printf("Recommended Browsing Domain %s %s", replyDomain, DomainMsg(resultType));
if (flags) printf(" Flags: %X", flags);
}
static void browse_reply(DNSServiceBrowserReplyResultType resultType,
- const char *replyName, const char *replyType, const char *replyDomain, DNSServiceDiscoveryReplyFlags flags, void *context)
+ const char *replyName, const char *replyType, const char *replyDomain, DNSServiceDiscoveryReplyFlags flags, void *context)
{
char *op = (resultType == DNSServiceBrowserReplyAddInstance) ? "Add" : "Rmv";
- (void)context; // Unused
+ (void)context; // Unused
if (num_printed++ == 0) printf("Timestamp A/R Flags %-24s %-24s %s\n", "Domain", "Service Type", "Instance Name");
printtimestamp();
printf("%s%6X %-24s %-24s %s\n", op, flags, replyDomain, replyType, replyName);
static void resolve_reply(struct sockaddr *interface, struct sockaddr *address, const char *txtRecord, DNSServiceDiscoveryReplyFlags flags, void *context)
{
- (void)interface; // Unused
- (void)context; // Unused
+ (void)interface; // Unused
+ (void)context; // Unused
if (address->sa_family != AF_INET && address->sa_family != AF_INET6)
printf("Unknown address family %d\n", address->sa_family);
else
{
- const char *src = txtRecord;
- printtimestamp();
-
- if (address->sa_family == AF_INET)
- {
- struct sockaddr_in *ip = (struct sockaddr_in *)address;
- union { uint32_t l; u_char b[4]; } addr = { ip->sin_addr.s_addr };
- union { uint16_t s; u_char b[2]; } port = { ip->sin_port };
- uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
- char ipstring[16];
- sprintf(ipstring, "%d.%d.%d.%d", addr.b[0], addr.b[1], addr.b[2], addr.b[3]);
- printf("Service can be reached at %-15s:%u", ipstring, PortAsNumber);
- }
- else if (address->sa_family == AF_INET6)
- {
- struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)address;
- u_int8_t *b = ip6->sin6_addr.__u6_addr.__u6_addr8;
- union { uint16_t s; u_char b[2]; } port = { ip6->sin6_port };
- uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
- char ipstring[40];
- char ifname[IF_NAMESIZE + 1] = "";
- sprintf(ipstring, "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+ const char *src = txtRecord;
+ printtimestamp();
+
+ if (address->sa_family == AF_INET)
+ {
+ struct sockaddr_in *ip = (struct sockaddr_in *)address;
+ union { uint32_t l; u_char b[4]; } addr = { ip->sin_addr.s_addr };
+ union { uint16_t s; u_char b[2]; } port = { ip->sin_port };
+ uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
+ char ipstring[16];
+ sprintf(ipstring, "%d.%d.%d.%d", addr.b[0], addr.b[1], addr.b[2], addr.b[3]);
+ printf("Service can be reached at %-15s:%u", ipstring, PortAsNumber);
+ }
+ else if (address->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)address;
+ u_int8_t *b = ip6->sin6_addr.__u6_addr.__u6_addr8;
+ union { uint16_t s; u_char b[2]; } port = { ip6->sin6_port };
+ uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
+ char ipstring[40];
+ char ifname[IF_NAMESIZE + 1] = "";
+ sprintf(ipstring, "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
b[0x0], b[0x1], b[0x2], b[0x3], b[0x4], b[0x5], b[0x6], b[0x7],
b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF]);
- if (ip6->sin6_scope_id) { ifname[0] = '%'; if_indextoname(ip6->sin6_scope_id, &ifname[1]); }
- printf("%s%s:%u", ipstring, ifname, PortAsNumber);
- }
+ if (ip6->sin6_scope_id) { ifname[0] = '%'; if_indextoname(ip6->sin6_scope_id, &ifname[1]); }
+ printf("%s%s:%u", ipstring, ifname, PortAsNumber);
+ }
if (flags) printf(" Flags: %X", flags);
- if (*src)
- {
- char txtInfo[64]; // Display at most first 64 characters of TXT record
- char *dst = txtInfo;
- const char *const lim = &txtInfo[sizeof(txtInfo)];
- while (*src && dst < lim-1)
- {
- if (*src == '\\') *dst++ = '\\'; // '\' displays as "\\"
- if (*src >= ' ') *dst++ = *src++; // Display normal characters as-is
- else
- {
- *dst++ = '\\'; // Display a backslash
- if (*src == 1) *dst++ = ' '; // String boundary displayed as "\ "
- else // Other chararacters displayed as "\0xHH"
- {
- static const char hexchars[16] = "0123456789ABCDEF";
- *dst++ = '0';
- *dst++ = 'x';
- *dst++ = hexchars[*src >> 4];
- *dst++ = hexchars[*src & 0xF];
- }
+ if (*src)
+ {
+ char txtInfo[64]; // Display at most first 64 characters of TXT record
+ char *dst = txtInfo;
+ const char *const lim = &txtInfo[sizeof(txtInfo)];
+ while (*src && dst < lim-1)
+ {
+ if (*src == '\\') *dst++ = '\\'; // '\' displays as "\\"
+ if (*src >= ' ') *dst++ = *src++; // Display normal characters as-is
+ else
+ {
+ *dst++ = '\\'; // Display a backslash
+ if (*src == 1) *dst++ = ' '; // String boundary displayed as "\ "
+ else // Other chararacters displayed as "\0xHH"
+ {
+ static const char hexchars[16] = "0123456789ABCDEF";
+ *dst++ = '0';
+ *dst++ = 'x';
+ *dst++ = hexchars[*src >> 4];
+ *dst++ = hexchars[*src & 0xF];
+ }
src++;
- }
- }
- *dst++ = 0;
- printf(" TXT %s", txtInfo);
- }
+ }
+ }
+ *dst++ = 0;
+ printf(" TXT %s", txtInfo);
+ }
printf("\n");
}
}
{
(void)timer; // Parameter not used
(void)info; // Parameter not used
-
- switch (operation)
- {
- case 'A':
- {
- switch (addtest)
- {
- case 0: printf("Adding Test HINFO record\n");
- record = DNSServiceRegistrationAddRecord(client, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120);
- addtest = 1;
- break;
- case 1: printf("Updating Test HINFO record\n");
- DNSServiceRegistrationUpdateRecord(client, record, sizeof(myhinfoX), &myhinfoX[0], 120);
- addtest = 2;
- break;
- case 2: printf("Removing Test HINFO record\n");
- DNSServiceRegistrationRemoveRecord(client, record);
- addtest = 0;
- break;
- }
- }
- break;
-
- case 'U':
- {
- if (updatetest[1] != 'Z') updatetest[1]++;
- else updatetest[1] = 'A';
- updatetest[0] = 3 - updatetest[0];
- updatetest[2] = updatetest[1];
- printf("Updating Test TXT record to %c\n", updatetest[1]);
- DNSServiceRegistrationUpdateRecord(client, 0, 1+updatetest[0], &updatetest[0], 120);
- }
- break;
-
- case 'N':
- {
- printf("Adding big NULL record\n");
- DNSServiceRegistrationAddRecord(client, T_NULL, sizeof(bigNULL), &bigNULL[0], 120);
- CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
- }
- break;
- }
- }
+
+ switch (operation)
+ {
+ case 'A':
+ {
+ switch (addtest)
+ {
+ case 0: printf("Adding Test HINFO record\n");
+ record = DNSServiceRegistrationAddRecord(client, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120);
+ addtest = 1;
+ break;
+ case 1: printf("Updating Test HINFO record\n");
+ DNSServiceRegistrationUpdateRecord(client, record, sizeof(myhinfoX), &myhinfoX[0], 120);
+ addtest = 2;
+ break;
+ case 2: printf("Removing Test HINFO record\n");
+ DNSServiceRegistrationRemoveRecord(client, record);
+ addtest = 0;
+ break;
+ }
+ }
+ break;
+
+ case 'U':
+ {
+ if (updatetest[1] != 'Z') updatetest[1]++;
+ else updatetest[1] = 'A';
+ updatetest[0] = 3 - updatetest[0];
+ updatetest[2] = updatetest[1];
+ printf("Updating Test TXT record to %c\n", updatetest[1]);
+ DNSServiceRegistrationUpdateRecord(client, 0, 1+updatetest[0], &updatetest[0], 120);
+ }
+ break;
+
+ case 'N':
+ {
+ printf("Adding big NULL record\n");
+ DNSServiceRegistrationAddRecord(client, T_NULL, sizeof(bigNULL), &bigNULL[0], 120);
+ CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
+ }
+ break;
+ }
+ }
static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
{
- (void)context; // Unused
- printf("Got a reply from the server: ");
- switch (errorCode)
- {
- case kDNSServiceDiscoveryNoError: printf("Name now registered and active\n"); break;
- case kDNSServiceDiscoveryNameConflict: printf("Name in use, please choose another\n"); exit(-1);
- default: printf("Error %d\n", errorCode); return;
- }
-
- if (operation == 'A' || operation == 'U' || operation == 'N')
- {
- CFRunLoopTimerContext myCFRunLoopTimerContext = { 0, 0, NULL, NULL, NULL };
- CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
- CFAbsoluteTimeGetCurrent() + 5.0, 5.0, 0, 1, // Next fire time, periodic interval, flags, and order
- myCFRunLoopTimerCallBack, &myCFRunLoopTimerContext);
- CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
- }
+ (void)context; // Unused
+ printf("Got a reply from the server: ");
+ switch (errorCode)
+ {
+ case kDNSServiceDiscoveryNoError: printf("Name now registered and active\n"); break;
+ case kDNSServiceDiscoveryNameConflict: printf("Name in use, please choose another\n"); exit(-1);
+ default: printf("Error %d\n", errorCode); return;
+ }
+
+ if (operation == 'A' || operation == 'U' || operation == 'N')
+ {
+ CFRunLoopTimerContext myCFRunLoopTimerContext = { 0, 0, NULL, NULL, NULL };
+ CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
+ CFAbsoluteTimeGetCurrent() + 5.0, 5.0, 0, 1, // Next fire time, periodic interval, flags, and order
+ myCFRunLoopTimerCallBack, &myCFRunLoopTimerContext);
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
+ }
}
//*************************************************************************************************************
setlinebuf(stdout); // Want to see lines as they appear, not block buffered
if (argc < 2) goto Fail; // Minimum command line is the command name and one argument
- operation = getopt(argc, (char * const *)argv, "EFBLRAUNTMI");
+ operation = getopt(argc, (char * const *)argv, "EFBLRAUNTMI");
if (operation == -1) goto Fail;
- switch (operation)
- {
- case 'E': printf("Looking for recommended registration domains:\n");
- client = DNSServiceDomainEnumerationCreate(1, regdom_reply, nil);
- break;
-
- case 'F': printf("Looking for recommended browsing domains:\n");
- client = DNSServiceDomainEnumerationCreate(0, browsedom_reply, nil);
- break;
-
- case 'B': if (argc < optind+1) goto Fail;
- dom = (argc < optind+2) ? "local" : argv[optind+1];
- if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
- printf("Browsing for %s%s\n", argv[optind+0], dom);
- client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil);
- break;
-
- case 'L': if (argc < optind+2) goto Fail;
- dom = (argc < optind+3) ? "" : argv[optind+2];
+ switch (operation)
+ {
+ case 'E': printf("Looking for recommended registration domains:\n");
+ client = DNSServiceDomainEnumerationCreate(1, regdom_reply, nil);
+ break;
+
+ case 'F': printf("Looking for recommended browsing domains:\n");
+ client = DNSServiceDomainEnumerationCreate(0, browsedom_reply, nil);
+ break;
+
+ case 'B': if (argc < optind+1) goto Fail;
+ dom = (argc < optind+2) ? "" : argv[optind+1]; // Missing domain argument is the same as empty string i.e. use system default(s)
+ if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
+ printf("Browsing for %s%s\n", argv[optind+0], dom);
+ client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil);
+ break;
+
+ case 'L': if (argc < optind+2) goto Fail;
+ dom = (argc < optind+3) ? "" : argv[optind+2];
if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local"
- printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom);
- client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil);
- break;
-
- case 'R': if (argc < optind+4) goto Fail;
- {
- char *nam = argv[optind+0];
- char *typ = argv[optind+1];
- char *dom = argv[optind+2];
- uint16_t PortAsNumber = atoi(argv[optind+3]);
- Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
- char txt[2048];
- char *ptr = txt;
- int i;
-
- if (nam[0] == '.' && nam[1] == 0) nam[0] = 0; // We allow '.' on the command line as a synonym for empty string
- if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
-
- // Copy all the TXT strings into one C string separated by ASCII-1 delimiters
- for (i = optind+4; i < argc; i++)
- {
- strcpy(ptr, argv[i]);
- ptr += strlen(argv[i]);
- *ptr++ = 1;
- }
- if (ptr > txt) ptr--;
- *ptr = 0;
-
- printf("Registering Service %s.%s%s port %s %s\n", nam, typ, dom, argv[optind+3], txt);
- client = DNSServiceRegistrationCreate(nam, typ, dom, registerPort.NotAnInteger, txt, reg_reply, nil);
- break;
- }
-
- case 'A':
- case 'U':
- case 'N': {
- Opaque16 registerPort = { { 0x12, 0x34 } };
- static const char TXT[] = "First String\001Second String\001Third String";
- printf("Registering Service Test._testupdate._tcp.local.\n");
- client = DNSServiceRegistrationCreate("Test", "_testupdate._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil);
- break;
- }
-
- case 'T': {
- Opaque16 registerPort = { { 0x23, 0x45 } };
- char TXT[1000];
- unsigned int i;
- for (i=0; i<sizeof(TXT)-1; i++)
- if ((i & 0x1F) == 0x1F) TXT[i] = 1; else TXT[i] = 'A' + (i >> 5);
- TXT[i] = 0;
- printf("Registering Service Test._testlargetxt._tcp.local.\n");
- client = DNSServiceRegistrationCreate("Test", "_testlargetxt._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil);
- break;
- }
-
- case 'M': {
- pid_t pid = getpid();
- Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
- static const char TXT1[] = "First String\001Second String\001Third String";
- static const char TXT2[] = "\x0D" "Fourth String" "\x0C" "Fifth String" "\x0C" "Sixth String";
- printf("Registering Service Test._testdualtxt._tcp.local.\n");
- client = DNSServiceRegistrationCreate("", "_testdualtxt._tcp.", "", registerPort.NotAnInteger, TXT1, reg_reply, nil);
- // use "sizeof(TXT2)-1" because we don't wan't the C compiler's null byte on the end of the string
- record = DNSServiceRegistrationAddRecord(client, T_TXT, sizeof(TXT2)-1, TXT2, 120);
- break;
- }
-
- case 'I': {
- pid_t pid = getpid();
- Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
- static const char TXT[] = "\x09" "Test Data";
- printf("Registering Service Test._testtxt._tcp.local.\n");
- client = DNSServiceRegistrationCreate("", "_testtxt._tcp.", "", registerPort.NotAnInteger, "", reg_reply, nil);
- if (client) DNSServiceRegistrationUpdateRecord(client, 0, 1+TXT[0], &TXT[0], 120);
- break;
- }
-
- default: goto Exit;
- }
-
- if (!client) { fprintf(stderr, "DNSService call failed\n"); return (-1); }
- if (AddDNSServiceClientToRunLoop(client) != 0) { fprintf(stderr, "AddDNSServiceClientToRunLoop failed\n"); return (-1); }
- printf("Talking to DNS SD Daemon at Mach port %d\n", DNSServiceDiscoveryMachPort(client));
+ printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom);
+ client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil);
+ break;
+
+ case 'R': if (argc < optind+4) goto Fail;
+ {
+ char *nam = argv[optind+0];
+ char *typ = argv[optind+1];
+ char *dom = argv[optind+2];
+ uint16_t PortAsNumber = atoi(argv[optind+3]);
+ Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
+ char txt[2048];
+ char *ptr = txt;
+ int i;
+
+ if (nam[0] == '.' && nam[1] == 0) nam[0] = 0; // We allow '.' on the command line as a synonym for empty string
+ if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
+
+ // Copy all the TXT strings into one C string separated by ASCII-1 delimiters
+ for (i = optind+4; i < argc; i++)
+ {
+ int len = strlen(argv[i]);
+ if (len > 255 || ptr + len + 1 >= txt + sizeof(txt)) break;
+ strcpy(ptr, argv[i]);
+ ptr += len;
+ *ptr++ = 1;
+ }
+ if (ptr > txt) ptr--;
+ *ptr = 0;
+
+ printf("Registering Service %s.%s%s port %s %s\n", nam, typ, dom, argv[optind+3], txt);
+ client = DNSServiceRegistrationCreate(nam, typ, dom, registerPort.NotAnInteger, txt, reg_reply, nil);
+ break;
+ }
+
+ case 'A':
+ case 'U':
+ case 'N': {
+ Opaque16 registerPort = { { 0x12, 0x34 } };
+ static const char TXT[] = "First String\001Second String\001Third String";
+ printf("Registering Service Test._testupdate._tcp.local.\n");
+ client = DNSServiceRegistrationCreate("Test", "_testupdate._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil);
+ break;
+ }
+
+ case 'T': {
+ Opaque16 registerPort = { { 0x23, 0x45 } };
+ char TXT[1000];
+ unsigned int i;
+ for (i=0; i<sizeof(TXT)-1; i++)
+ if ((i & 0x1F) == 0x1F) TXT[i] = 1; else TXT[i] = 'A' + (i >> 5);
+ TXT[i] = 0;
+ printf("Registering Service Test._testlargetxt._tcp.local.\n");
+ client = DNSServiceRegistrationCreate("Test", "_testlargetxt._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil);
+ break;
+ }
+
+ case 'M': {
+ pid_t pid = getpid();
+ Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
+ static const char TXT1[] = "First String\001Second String\001Third String";
+ static const char TXT2[] = "\x0D" "Fourth String" "\x0C" "Fifth String" "\x0C" "Sixth String";
+ printf("Registering Service Test._testdualtxt._tcp.local.\n");
+ client = DNSServiceRegistrationCreate("", "_testdualtxt._tcp.", "", registerPort.NotAnInteger, TXT1, reg_reply, nil);
+ // use "sizeof(TXT2)-1" because we don't wan't the C compiler's null byte on the end of the string
+ record = DNSServiceRegistrationAddRecord(client, T_TXT, sizeof(TXT2)-1, TXT2, 120);
+ break;
+ }
+
+ case 'I': {
+ pid_t pid = getpid();
+ Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
+ static const char TXT[] = "\x09" "Test Data";
+ printf("Registering Service Test._testtxt._tcp.local.\n");
+ client = DNSServiceRegistrationCreate("", "_testtxt._tcp.", "", registerPort.NotAnInteger, "", reg_reply, nil);
+ if (client) DNSServiceRegistrationUpdateRecord(client, 0, 1+TXT[0], &TXT[0], 120);
+ break;
+ }
+
+ default: goto Exit;
+ }
+
+ if (!client) { fprintf(stderr, "DNSService call failed\n"); return (-1); }
+ if (AddDNSServiceClientToRunLoop(client) != 0) { fprintf(stderr, "AddDNSServiceClientToRunLoop failed\n"); return (-1); }
+ printf("Talking to DNS SD Daemon at Mach port %d\n", DNSServiceDiscoveryMachPort(client));
CFRunLoopRun();
-
- // Be sure to deallocate the dns_service_discovery_ref when you're finished
- // Note: What other cleanup has to be done here?
- // We should probably invalidate, remove and release our CFRunLoopSourceRef?
- DNSServiceDiscoveryDeallocate(client);
-
+
+ // Be sure to deallocate the dns_service_discovery_ref when you're finished
+ // Note: What other cleanup has to be done here?
+ // We should probably invalidate, remove and release our CFRunLoopSourceRef?
+ DNSServiceDiscoveryDeallocate(client);
+
Exit:
return 0;
fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", progname);
return 0;
}
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) mDNS " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
*
- * @APPLE_LICENSE_HEADER_START@
+ * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*
* Formatting notes:
* This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
Change History (most recent first):
$Log: daemon.c,v $
-Revision 1.255.2.1 2005/07/22 21:45:04 ksekar
-Fix GCC 4.0/Intel compiler warnings
-
-Revision 1.255 2005/03/09 00:48:43 cheshire
-<rdar://problem/4015157> QU packets getting sent too early on wake from sleep
-Move "m->p->NetworkChanged = 0;" line from caller to callee
-
-Revision 1.254 2005/03/03 04:34:19 cheshire
-<rdar://problem/4025973> Bonjour name conflict dialog appears during MacBuddy
-
-Revision 1.253 2005/03/03 03:55:09 cheshire
-<rdar://problem/3862944> Name collision notifications should be localized
-
-Revision 1.252 2005/02/23 02:29:17 cheshire
-<rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
-Minor refinements, better variable names, improved comments
-
-Revision 1.251 2005/02/21 21:31:24 ksekar
-<rdar://problem/4015162> changed LogMsg to debugf
-
-Revision 1.250 2005/02/19 01:25:04 cheshire
-<rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
-Further refinements
-
-Revision 1.249 2005/02/19 00:28:45 cheshire
-<rdar://problem/4005191> "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed
-
-Revision 1.248 2005/02/19 00:18:34 cheshire
-Confusing variable name -- alertMessage should be called alertHeader
-
-Revision 1.247 2005/02/15 02:13:49 cheshire
-If we did registerBootstrapService() when starting, then we must do
-destroyBootstrapService() before exiting, or Mach init will keep restarting us.
-
-Revision 1.246 2005/02/03 00:44:37 cheshire
-<rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
-
-Revision 1.245 2005/02/01 19:56:47 ksekar
-Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
-
-Revision 1.244 2005/01/28 00:34:49 cheshire
-Turn off "Starting time value" log message
-
-Revision 1.243 2005/01/27 17:46:58 cheshire
-Added comment about CFSocketInvalidate closing the underlying socket
-
-Revision 1.242 2005/01/27 00:10:58 cheshire
-<rdar://problem/3967867> Name change log messages every time machine boots
-
-Revision 1.241 2005/01/25 17:28:06 ksekar
-<rdar://problem/3971467> Should not return "local" twice for domain enumeration
-
-Revision 1.240 2005/01/21 02:39:18 cheshire
-Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
-
-Revision 1.239 2005/01/20 00:25:01 cheshire
-Improve validatelists() log message generation
-
-Revision 1.238 2005/01/19 19:15:35 ksekar
-Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
-
-Revision 1.237 2005/01/19 03:33:09 cheshire
-<rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
-
-Revision 1.236 2005/01/19 03:16:38 cheshire
-<rdar://problem/3961051> CPU Spin in mDNSResponder
-Improve detail of "Task Scheduling Error" diagnostic messages
-
-Revision 1.235 2005/01/15 00:56:41 ksekar
-<rdar://problem/3954575> Unicast services don't disappear when logging
-out of VPN
-
-Revision 1.234 2005/01/10 03:42:30 ksekar
-Clarify debugf
-
-Revision 1.233 2004/12/18 00:53:46 cheshire
-Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
-
-Revision 1.232 2004/12/17 23:37:48 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.231 2004/12/17 04:13:38 cheshire
-Removed debugging check
-
-Revision 1.230 2004/12/17 04:09:30 cheshire
-<rdar://problem/3191011> Switch mDNSResponder to launchd
-
-Revision 1.229 2004/12/16 21:51:36 cheshire
-Remove some startup messages
-
-Revision 1.228 2004/12/16 20:13:01 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.227 2004/12/10 13:52:57 cheshire
-<rdar://problem/3909995> Turn off SIGPIPE signals
-
-Revision 1.226 2004/12/10 05:27:26 cheshire
-<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
-
-Revision 1.225 2004/12/10 04:28:29 cheshire
-<rdar://problem/3914406> User not notified of name changes for services using new UDS API
-
-Revision 1.224 2004/12/10 00:41:05 cheshire
-Adjust alignment of log messages
-
-Revision 1.223 2004/12/07 20:42:34 cheshire
-Add explicit context parameter to mDNS_RemoveRecordFromService()
-
-Revision 1.222 2004/12/06 21:15:23 ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.221 2004/11/30 03:24:04 cheshire
-<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
-
-Revision 1.220 2004/11/29 23:34:31 cheshire
-On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero
-is crude, and effectively halves the time resolution. The more selective NonZeroTime() function
-only nudges the time value to 1 if the interval calculation happens to result in the value zero.
-
-Revision 1.219 2004/11/25 01:00:56 cheshire
-Checkin 1.217 not necessary
-
-Revision 1.218 2004/11/24 20:27:19 cheshire
-Add missing "err" parameter in LogMsg() call
-
-Revision 1.217 2004/11/24 17:55:01 ksekar
-Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
-
-Revision 1.216 2004/11/24 00:10:44 cheshire
-<rdar://problem/3869241> For unicast operations, verify that service types are legal
-
-Revision 1.215 2004/11/23 22:33:01 cheshire
-<rdar://problem/3654910> Remove temporary workaround code for iChat
+Revision 1.344 2007/09/29 01:06:17 mcguire
+<rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
-Revision 1.214 2004/11/23 22:13:59 cheshire
-<rdar://problem/3886293> Subtype advertising broken for Mach API
+Revision 1.343 2007/09/24 05:02:41 cheshire
+Debugging: In SIGINFO output, indicate explicitly when a given section is empty
-Revision 1.213 2004/11/23 06:12:55 cheshire
-<rdar://problem/3871405> Update wording for name conflict dialogs
+Revision 1.342 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-Revision 1.212 2004/11/23 05:15:37 cheshire
-<rdar://problem/3875830> Computer Name in use message garbled
+Revision 1.341 2007/09/12 01:22:13 cheshire
+Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
-Revision 1.211 2004/11/23 05:00:41 cheshire
-<rdar://problem/3874629> Name conflict log message should not have ".local" appended
+Revision 1.340 2007/09/07 22:44:03 mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
-Revision 1.210 2004/11/03 03:45:17 cheshire
-<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
+Revision 1.339 2007/09/06 19:08:29 cheshire
+LogAllOperations check needs to be "#if LogAllOperations || MDNS_DEBUGMSGS"
-Revision 1.209 2004/11/03 02:25:50 cheshire
-<rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
+Revision 1.338 2007/09/05 23:34:27 mcguire
+Revert logging change
-Revision 1.208 2004/11/03 01:54:14 cheshire
-Update debugging messages
+Revision 1.337 2007/09/05 20:45:50 cheshire
+Added list of KQSocketEventSources in SIGINFO output
-Revision 1.207 2004/11/02 23:58:19 cheshire
-<rdar://problem/2974905> mDNSResponder does not inform user of name collisions
+Revision 1.336 2007/08/31 17:15:37 cheshire
+Reordered startup log messages so that "mDNSResponder ... starting" is the first message
-Revision 1.206 2004/10/28 02:40:47 cheshire
-Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event)
+Revision 1.335 2007/08/31 02:00:16 cheshire
+Added comment explaining use of zero-width non-breaking space character to tag literal strings
-Revision 1.205 2004/10/28 02:21:01 cheshire
-<rdar://problem/3856500> Improve mDNSResponder signal handling
-Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9)
-Added SIGUSR1 to simulate a network change notification from System Configuration Framework
+Revision 1.334 2007/08/24 23:40:24 cheshire
+Added comment about FreeServiceInstance
-Revision 1.204 2004/10/27 01:57:21 cheshire
-Add check of m->p->InterfaceList
+Revision 1.333 2007/08/23 21:02:35 cheshire
+SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
-Revision 1.203 2004/10/26 04:31:44 cheshire
-Rename CountSubTypes() as ChopSubTypes()
+Revision 1.332 2007/08/22 23:54:54 mcguire
+<rdar://problem/5422558> BTMM: mDNSResponder should be able to run from the cmdline
-Revision 1.202 2004/10/26 01:29:18 cheshire
-Use "#if 0" instead of commenting out code
+Revision 1.331 2007/08/18 01:02:03 mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
-Revision 1.201 2004/10/25 21:41:39 ksekar
-<rdar://problem/3852958> wide-area name conflicts can cause crash
+Revision 1.330 2007/08/10 22:25:57 mkrochma
+<rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
-Revision 1.200 2004/10/22 01:03:55 cheshire
-<rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
-Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails
+Revision 1.329 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-Revision 1.199 2004/10/19 21:33:19 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+Revision 1.328 2007/07/27 22:43:37 cheshire
+Improved mallocL/freeL "suspiciously large" debugging messages
-Revision 1.198 2004/10/15 23:00:18 ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
+Revision 1.327 2007/07/27 19:30:41 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
-Revision 1.197 2004/10/12 23:38:59 ksekar
-<rdar://problem/3837065> remove unnecessary log message
+Revision 1.326 2007/07/24 17:23:33 cheshire
+<rdar://problem/5357133> Add list validation checks for debugging
-Revision 1.196 2004/10/04 05:56:04 cheshire
-<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
+Revision 1.325 2007/07/11 23:43:43 cheshire
+Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
-Revision 1.195 2004/09/30 00:24:59 ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.324 2007/07/11 22:44:40 cheshire
+<rdar://problem/5328801> SIGHUP should purge the cache
-Revision 1.194 2004/09/26 23:20:35 ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.323 2007/07/11 03:01:50 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Revision 1.193 2004/09/23 23:35:27 cheshire
-Update error message
+Revision 1.322 2007/07/06 18:58:16 cheshire
+Check m->NextScheduledNATOp in ShowTaskSchedulingError()
-Revision 1.192 2004/09/21 23:40:12 ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+Revision 1.321 2007/07/02 21:54:20 cheshire
+Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks
-Revision 1.191 2004/09/21 21:05:12 cheshire
-Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
-into mDNSShared/uds_daemon.c
+Revision 1.320 2007/06/28 21:16:27 cheshire
+Rename "m->nextevent" as more informative "m->NextuDNSEvent"
-Revision 1.190 2004/09/21 19:51:15 cheshire
-Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c
+Revision 1.319 2007/06/22 20:47:08 cheshire
+<rdar://problem/5285417> DOS charset changes from CP932 to CP850 after Computer Name conflict
+Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set
-Revision 1.189 2004/09/21 18:17:23 cheshire
-<rdar://problem/3785400> Add version info to mDNSResponder
+Revision 1.318 2007/06/20 01:45:40 cheshire
+When showing dormant interfaces, display last-seen IP address for that dormant interface
-Revision 1.188 2004/09/20 21:45:27 ksekar
-Mach IPC cleanup
+Revision 1.317 2007/06/20 01:10:12 cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-Revision 1.187 2004/09/17 01:08:52 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.316 2007/06/19 19:27:11 cheshire
+<rdar://problem/5141540> Sandbox mDNSResponder
+Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing
-Revision 1.186 2004/09/16 00:24:49 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.315 2007/06/15 21:54:51 cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-Revision 1.185 2004/08/25 02:01:45 cheshire
-<rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
+Revision 1.314 2007/06/15 19:23:17 cheshire
+<rdar://problem/5254053> mDNSResponder renames my host without asking
+Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
-Revision 1.184 2004/08/19 19:04:12 ksekar
-<rdar://problem/3767546>: mDNSResponder crashes when adding a record to a service
+Revision 1.313 2007/05/25 16:02:05 cheshire
+When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations
-Revision 1.183 2004/08/14 03:22:42 cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.312 2007/05/22 19:07:21 cheshire
+Add comment explaining RR_CACHE_SIZE calculation
-Revision 1.182 2004/08/13 23:57:59 cheshire
-Get rid of non-portable "_UNUSED"
+Revision 1.311 2007/05/15 21:47:21 cheshire
+Get rid of "#pragma unused(m)"
-Revision 1.181 2004/08/11 02:02:26 cheshire
-Remove "mDNS *globalInstance" parameter from udsserver_init();
-Move CheckForDuplicateRegistrations to uds_daemon.c
+Revision 1.310 2007/05/08 00:56:17 cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
-Revision 1.180 2004/07/13 21:24:25 rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.309 2007/04/30 21:33:38 cheshire
+Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
+is iterating through the m->ServiceRegistrations list
-Revision 1.179 2004/06/19 00:02:54 cheshire
-Restore fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
+Revision 1.308 2007/04/28 01:31:59 cheshire
+Improve debugging support for catching memory corruption problems
-Revision 1.178 2004/06/18 19:10:00 cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.307 2007/04/24 18:32:00 cheshire
+Grab a copy of KQtask string pointer in case KQcallback deletes the task
-Revision 1.177 2004/06/16 23:14:46 ksekar
-<rdar://problem/3693816> Remove fix for <rdar://problem/3548256> Should not allow empty string for resolve domain
+Revision 1.306 2007/04/22 19:11:51 cheshire
+Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash
+if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c
+from the project and just using simple vanilla C linked-list manipulation instead.
-Revision 1.176 2004/06/11 20:27:42 cheshire
-Rename "SocketRef" as "cfs" to avoid conflict with other plaforms
+Revision 1.305 2007/04/22 06:02:03 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.175 2004/06/10 20:23:21 cheshire
-Also list interfaces in SIGINFO output
+Revision 1.304 2007/04/21 21:47:47 cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
-Revision 1.174 2004/06/08 18:54:48 ksekar
-<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
+Revision 1.303 2007/04/18 00:50:47 cheshire
+<rdar://problem/5141540> Sandbox mDNSResponder
-Revision 1.173 2004/06/08 17:35:12 cheshire
-<rdar://problem/3683988> Detect and report if mDNSResponder uses too much CPU
+Revision 1.302 2007/04/07 01:01:48 cheshire
+<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
-Revision 1.172 2004/06/05 00:04:26 cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+Revision 1.301 2007/04/05 19:13:48 cheshire
+Use better name in SCPreferencesCreate
-Revision 1.171 2004/06/04 08:58:30 ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
+Revision 1.300 2007/04/04 21:22:18 cheshire
+Suppress "Local Hostname changed" syslog message when name has not actually changed
-Revision 1.170 2004/05/30 20:01:50 ksekar
-<rdar://problem/3668635>: wide-area default registrations should be in
-.local too - fixed service registration when clients pass an explicit
-domain (broken by previous checkin)
+Revision 1.299 2007/04/03 19:19:33 cheshire
+Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field
-Revision 1.169 2004/05/30 01:30:16 ksekar
-<rdar://problem/3668635>: wide-area default registrations should be in
-.local too
+Revision 1.298 2007/03/30 21:51:45 cheshire
+Minor code tidying
-Revision 1.168 2004/05/18 23:51:26 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.297 2007/03/27 22:47:19 cheshire
+On memory corruption, if ForceAlerts is set, force a crash to get a stack trace
-Revision 1.167 2004/05/14 16:39:47 ksekar
-Browse for iChat locally for now.
+Revision 1.296 2007/03/24 01:23:29 cheshire
+Call validator for uDNS data structures
-Revision 1.166 2004/05/13 21:33:52 ksekar
-Clean up non-local registration control via config file. Force iChat
-registrations to be local for now.
+Revision 1.295 2007/03/20 23:32:49 cheshire
+Minor textual tidying
-Revision 1.165 2004/05/13 04:54:20 ksekar
-Unified list copy/free code. Added symetric list for
+Revision 1.294 2007/03/07 02:50:50 cheshire
+<rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
-Revision 1.164 2004/05/12 22:03:08 ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms. Changed call to return a copy of the list
-to avoid shared memory issues. Added a routine to free the list.
+Revision 1.293 2007/03/06 22:59:01 cheshire
+<rdar://problem/4157921> Security: Null dereference possible in daemon.c
-Revision 1.163 2004/05/12 02:03:25 ksekar
-Non-local domains will only be browsed by default, and show up in
-_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
+Revision 1.292 2007/02/28 21:55:10 cheshire
+<rdar://problem/3862944> UI: Name conflict notifications should be localized
+Additional fix: We were not getting our NotificationCallBackDismissed messages
+because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop.
+(We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.)
-Revision 1.162 2004/04/14 23:09:29 ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.291 2007/02/28 03:51:24 cheshire
+<rdar://problem/3862944> UI: Name conflict notifications should be localized
+Moved curly quotes out of the literal text and into the localized text, so they
+can be replaced with alternate characters as appropriate for other languages.
-Revision 1.161 2004/04/07 01:20:04 cheshire
-Hash slot value should be unsigned
+Revision 1.290 2007/02/14 01:58:19 cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-Revision 1.160 2004/04/06 19:51:24 cheshire
-<rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
-After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist.
+Revision 1.289 2007/02/07 19:32:00 cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-Revision 1.159 2004/04/03 01:36:55 cheshire
-<rdar://problem/3605898> mDNSResponder will not launch if "nobody" user doesn't exist.
-If "nobody" user doesn't exist, log a message and continue as "root"
+Revision 1.288 2007/02/07 01:01:24 cheshire
+<rdar://problem/3956518> Need to go native with launchd
+Additional refinements -- was unnecessarily calling launch_data_free()
-Revision 1.158 2004/04/02 21:39:05 cheshire
-Fix errors in comments
+Revision 1.287 2007/02/06 19:06:48 cheshire
+<rdar://problem/3956518> Need to go native with launchd
-Revision 1.157 2004/03/19 18:49:10 ksekar
-Increased size check in freeL() to account for LargeCacheRecord
-structs larger than 8k
+Revision 1.286 2007/01/06 01:00:33 cheshire
+Improved SIGINFO output
-Revision 1.156 2004/03/19 18:19:19 ksekar
-Fixed daemon.c to compile with malloc debugging turned on.
+Revision 1.285 2007/01/05 08:30:47 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.155 2004/03/13 01:57:34 ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.284 2007/01/05 05:44:35 cheshire
+Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
+so that mDNSPosix embedded clients will compile again
-Revision 1.154 2004/03/12 08:42:47 cheshire
-<rdar://problem/3548256>: Should not allow empty string for resolve domain
+Revision 1.283 2007/01/04 23:11:14 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-Revision 1.153 2004/03/12 08:08:51 cheshire
-Update comments
+Revision 1.282 2006/12/21 00:09:45 cheshire
+Use mDNSPlatformMemZero instead of bzero
-Revision 1.152 2004/02/05 19:39:29 cheshire
-Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
-so that all platforms get this functionality
+Revision 1.281 2006/11/18 05:01:32 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
-Revision 1.151 2004/02/03 22:35:34 cheshire
-<rdar://problem/3548256>: Should not allow empty string for resolve domain
+Revision 1.280 2006/11/10 00:54:16 cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
-Revision 1.150 2004/01/28 21:14:23 cheshire
-Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
+Revision 1.279 2006/11/02 17:44:01 cheshire
+No longer have a separate uDNS ActiveQueries list
-Revision 1.149 2004/01/28 02:30:08 ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane. Stopped sending unicast messages on
-every interface. Fixed unicast resolving via mach-port API.
+Revision 1.278 2006/10/05 04:04:24 herscher
+Remove embedded uDNS_info struct from DNSQuestion_struct
-Revision 1.148 2004/01/25 00:03:20 cheshire
-Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
+Revision 1.277 2006/09/21 21:01:24 cheshire
+Change 'autorename' to more accurate name 'renameonmemfree'
-Revision 1.147 2004/01/19 19:51:46 cheshire
-Fix compiler error (mixed declarations and code) on some versions of Linux
+Revision 1.276 2006/09/17 19:12:02 cheshire
+Further changes for removal of uDNS_info substructure from mDNS_struct
-Revision 1.146 2003/12/08 21:00:46 rpantos
-Changes to support mDNSResponder on Linux.
+Revision 1.275 2006/09/15 21:20:16 cheshire
+Remove uDNS_info substructure from mDNS_struct
-Revision 1.145 2003/12/05 22:08:07 cheshire
-Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1)
+Revision 1.274 2006/08/14 23:24:39 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.144 2003/11/19 23:21:08 ksekar
-<rdar://problem/3486646>: config change handler not called for dns-sd services
+Revision 1.273 2006/07/30 05:43:19 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Problems using KQueueFD with select() -- for now we'll stick to pure kevent()
-Revision 1.143 2003/11/14 21:18:32 cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+Revision 1.272 2006/07/27 03:24:35 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinement: Declare KQueueEntry parameter "const"
-Revision 1.142 2003/11/08 22:18:29 cheshire
-<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+Revision 1.271 2006/07/27 02:59:26 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
+after releasing BigMutex, in case actions it took have resulted in new work for the
+kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
+add new active interfaces to its list, and consequently schedule queries to be sent).
-Revision 1.141 2003/11/07 02:30:57 cheshire
-Also check per-slot cache use counts in SIGINFO state log
+Revision 1.270 2006/07/25 17:16:36 mkrochma
+Quick fix to solve kqueue related crashes and hangs
-Revision 1.140 2003/10/21 19:58:26 cheshire
-<rdar://problem/3459037> Syslog messages should show TTL as signed (for overdue records)
+Revision 1.269 2006/07/22 06:11:37 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Revision 1.139 2003/10/21 00:10:18 rpantos
-<rdar://problem/3409401>: mDNSResponder should not run as root
+Revision 1.268 2006/07/15 02:01:32 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
-Revision 1.138 2003/10/07 20:16:58 cheshire
-Shorten syslog message a bit
+Revision 1.267 2006/07/07 01:09:10 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-Revision 1.137 2003/09/23 02:12:43 cheshire
-Also include port number in list of services registered via new UDS API
+Revision 1.266 2006/07/05 23:34:53 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Revision 1.136 2003/09/23 02:07:25 cheshire
-Include port number in DNSServiceRegistration START/STOP messages
+Revision 1.265 2006/06/29 07:32:08 cheshire
+Added missing LogOperation logging for DNSServiceBrowse results
-Revision 1.135 2003/09/23 01:34:02 cheshire
-In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations
+Revision 1.264 2006/06/29 05:33:30 cheshire
+<rdar://problem/4607043> mDNSResponder conditional compilation options
-Revision 1.134 2003/08/21 20:01:37 cheshire
-<rdar://problem/3387941> Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog
+Revision 1.263 2006/06/08 23:23:48 cheshire
+Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
-Revision 1.133 2003/08/20 23:39:31 cheshire
-<rdar://problem/3344098> Review syslog messages, and remove as appropriate
+Revision 1.262 2006/03/18 21:49:11 cheshire
+Added comment in ShowTaskSchedulingError(mDNS *const m)
-Revision 1.132 2003/08/20 01:44:56 cheshire
-Fix errors in LogOperation() calls (only used for debugging)
+Revision 1.261 2006/01/06 01:22:28 cheshire
+<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
-Revision 1.131 2003/08/19 05:39:43 cheshire
-<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
-
-Revision 1.130 2003/08/16 03:39:01 cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
-
-Revision 1.129 2003/08/15 20:16:03 cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
- Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
- compute a hash of the rdata and store the hash in the ResourceRecord object.
-
-Revision 1.128 2003/08/14 19:30:36 cheshire
-<rdar://problem/3378473> Include list of cache records in SIGINFO output
-
-Revision 1.127 2003/08/14 02:18:21 cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.126 2003/08/12 19:56:25 cheshire
-Update to APSL 2.0
-
-Revision 1.125 2003/08/08 18:36:04 cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
-
-Revision 1.124 2003/07/25 18:28:23 cheshire
-Minor fix to error messages in syslog: Display string parameters with quotes
-
-Revision 1.123 2003/07/23 17:45:28 cheshire
-<rdar://problem/3339388> mDNSResponder leaks a bit
-Don't allocate memory for the reply until after we've verified that the reply is valid
-
-Revision 1.122 2003/07/23 00:00:04 cheshire
-Add comments
-
-Revision 1.121 2003/07/20 03:38:51 ksekar
-<rdar://problem/3320722> Completed support for Unix-domain socket based API.
-
-Revision 1.120 2003/07/18 00:30:00 cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
-
-Revision 1.119 2003/07/17 19:08:58 cheshire
-<rdar://problem/3332153> Remove calls to enable obsolete UDS code
-
-Revision 1.118 2003/07/15 21:12:28 cheshire
-Added extra debugging checks in validatelists() (not used in final shipping version)
-
-Revision 1.117 2003/07/15 01:55:15 cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
-
-Revision 1.116 2003/07/02 21:19:51 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.115 2003/07/02 02:41:24 cheshire
-<rdar://problem/2986146> mDNSResponder needs to start with a smaller cache and then grow it as needed
-
-Revision 1.114 2003/07/01 21:10:20 cheshire
-Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112
-
-Revision 1.113 2003/06/28 17:27:43 vlubet
-<rdar://problem/3221246> Redirect standard input, standard output, and
-standard error file descriptors to /dev/null just like any other
-well behaved daemon
-
-Revision 1.112 2003/06/25 23:42:19 ksekar
-<rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
-Reviewed by: Stuart Cheshire
-Added files necessary to implement Unix domain sockets based enhanced
-DNS-SD APIs, and integrated with existing Mach-port based daemon.
-
-Revision 1.111 2003/06/11 01:02:43 cheshire
-<rdar://problem/3287858> mDNSResponder binary compatibility
-Make single binary that can run on both Jaguar and Panther.
-
-Revision 1.110 2003/06/10 01:14:11 cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
-
-Revision 1.109 2003/06/06 19:53:43 cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
-
-Revision 1.108 2003/06/06 14:08:06 cheshire
-For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle()
-
-Revision 1.107 2003/05/29 05:44:55 cheshire
-Minor fixes to log messages
-
-Revision 1.106 2003/05/27 18:30:55 cheshire
-<rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
-Dean Reece suggested SIGINFO is more appropriate than SIGHUP
-
-Revision 1.105 2003/05/26 03:21:29 cheshire
-Tidy up address structure naming:
-mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.104 2003/05/26 00:42:06 cheshire
-<rdar://problem/3268876> Temporarily include mDNSResponder version in packets
-
-Revision 1.103 2003/05/23 23:07:44 cheshire
-<rdar://problem/3268199> Must not write to stderr when running as daemon
-
-Revision 1.102 2003/05/22 01:32:31 cheshire
-Fix typo in Log message format string
-
-Revision 1.101 2003/05/22 00:26:55 cheshire
-<rdar://problem/3239284> DNSServiceRegistrationCreate() should return error on dup
-Modify error message to explain that this is technically legal, but may indicate a bug.
-
-Revision 1.100 2003/05/21 21:02:24 ksekar
-<rdar://problem/3247035>: Service should be prefixed
-Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main
-Mach message port to "com.apple.mDNSResponder.
-
-Revision 1.99 2003/05/21 17:33:49 cheshire
-Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.)
-
-Revision 1.98 2003/05/20 00:33:07 cheshire
-<rdar://problem/3262962> Need a way to easily examine current mDNSResponder state
-SIGHUP now writes state summary to syslog
-
-Revision 1.97 2003/05/08 00:19:08 cheshire
-<rdar://problem/3250330> Forgot to set "err = mStatus_BadParamErr" in a couple of places
-
-Revision 1.96 2003/05/07 22:10:46 cheshire
-<rdar://problem/3250330> Add a few more error logging messages
-
-Revision 1.95 2003/05/07 19:20:17 cheshire
-<rdar://problem/3251391> Add version number to mDNSResponder builds
-
-Revision 1.94 2003/05/07 00:28:18 cheshire
-<rdar://problem/3250330> Need to make mDNSResponder more defensive against bad clients
-
-Revision 1.93 2003/05/06 00:00:49 cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.92 2003/04/04 20:38:57 cheshire
-Add $Log header
-
- */
+*/
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <unistd.h>
#include <paths.h>
#include <fcntl.h>
+#include <launch.h>
#include <pwd.h>
+#include <sys/event.h>
+#include <pthread.h>
+#include <sandbox.h>
#include <SystemConfiguration/SCPreferencesSetSpecific.h>
#include "DNSServiceDiscoveryRequestServer.h"
#include "DNSServiceDiscoveryReply.h"
+#include "uDNS.h"
#include "DNSCommon.h"
#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
#include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
-#include "GenLinkedList.h"
-
#include <DNSServiceDiscovery/DNSServiceDiscovery.h>
+#include "helper.h"
//*************************************************************************************************************
// Macros
//*************************************************************************************************************
// Globals
-#define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
-#define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
static mDNS_PlatformSupport PlatformStorage;
-// Start off with a default cache of 16K (about 100 records)
+// Start off with a default cache of 16K (99 records)
+// Each time we grow the cache we add another 99 records
+// 99 * 164 = 16236 bytes.
+// This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead
#define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
static CacheEntity rrcachestorage[RR_CACHE_SIZE];
static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
+static mach_port_t m_port = MACH_PORT_NULL;
static mach_port_t client_death_port = MACH_PORT_NULL;
static mach_port_t signal_port = MACH_PORT_NULL;
static mach_port_t server_priv_port = MACH_PORT_NULL;
+static dnssd_sock_t launchd_fd = dnssd_InvalidSocket;
+
// mDNS Mach Message Timeout, in milliseconds.
// We need this to be short enough that we don't deadlock the mDNSResponder if a client
// fails to service its mach message queue, but long enough to give a well-written
// even extra-slow clients a fair chance before we cut them off.
#define MDNS_MM_TIMEOUT 250
-static int restarting_via_mach_init = 0;
-static int started_via_launchdaemon = 0;
+static int restarting_via_mach_init = 0; // Used on Jaguar/Panther when daemon is started via mach_init mechanism
+static int started_via_launchdaemon = 0; // Indicates we're running on Tiger or later, where daemon is managed by launchd
static int OSXVers;
+static CFRunLoopRef CFRunLoop;
+
//*************************************************************************************************************
// Active client list structures
struct ServiceInstance *next;
mach_port_t ClientMachPort;
mDNSBool autoname; // Set if this name is tied to the Computer Name
- mDNSBool autorename; // Set if we just got a name conflict and now need to automatically pick a new name
+ mDNSBool renameonmemfree; // Set if we just got a name conflict and now need to automatically pick a new name
domainlabel name;
domainname domain;
ServiceRecordSet srs;
static DNSServiceResolver *DNSServiceResolverList = NULL;
static DNSServiceRegistration *DNSServiceRegistrationList = NULL;
+// We keep a list of client-supplied event sources in KQSocketEventSource records
+typedef struct KQSocketEventSource
+ {
+ struct KQSocketEventSource *next;
+ int fd;
+ KQueueEntry kqs;
+ } KQSocketEventSource;
+
+static KQSocketEventSource *gEventSources;
+
//*************************************************************************************************************
// General Utility Functions
-#if MACOSX_MDNS_MALLOC_DEBUGGING
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
char _malloc_options[] = "AXZ";
+mDNSexport void LogMemCorruption(const char *format, ...)
+ {
+ char buffer[512];
+ va_list ptr;
+ va_start(ptr,format);
+ buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+ va_end(ptr);
+ LogMsg("!!!! %s !!!!", buffer);
+ NotifyOfElusiveBug("Memory Corruption", buffer);
+#if ForceAlerts
+ *(long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
+#endif
+ }
+
mDNSlocal void validatelists(mDNS *const m)
{
- DNSServiceDomainEnumeration *e;
- DNSServiceBrowser *b;
- DNSServiceResolver *l;
- DNSServiceRegistration *r;
- AuthRecord *rr;
- CacheGroup *cg;
- CacheRecord *cr;
- DNSQuestion *q;
- mDNSu32 slot;
- NetworkInterfaceInfoOSX *i;
+ // Check local lists
+ KQSocketEventSource *k;
+ for (k = gEventSources; k; k=k->next)
+ if (k->next == (KQSocketEventSource *)~0 || k->fd < 0)
+ LogMemCorruption("gEventSources: %p is garbage (%d)", k, k->fd);
+ // Check Mach client lists
+ DNSServiceDomainEnumeration *e;
for (e = DNSServiceDomainEnumerationList; e; e=e->next)
- if (e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
- LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e, e->ClientMachPort);
+ if (e->next == (DNSServiceDomainEnumeration *)~0 || e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0)
+ LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e, e->ClientMachPort);
+ DNSServiceBrowser *b;
for (b = DNSServiceBrowserList; b; b=b->next)
- if (b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0)
- LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b, b->ClientMachPort);
+ if (b->next == (DNSServiceBrowser *)~0 || b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0)
+ LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b, b->ClientMachPort);
+ DNSServiceResolver *l;
for (l = DNSServiceResolverList; l; l=l->next)
- if (l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0)
- LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l, l->ClientMachPort);
+ if (l->next == (DNSServiceResolver *)~0 || l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0)
+ LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l, l->ClientMachPort);
+ DNSServiceRegistration *r;
for (r = DNSServiceRegistrationList; r; r=r->next)
- if (r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0)
- LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r, r->ClientMachPort);
+ if (r->next == (DNSServiceRegistration *)~0 || r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0)
+ LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r, r->ClientMachPort);
+
+ // Check Unix Domain Socket client lists (uds_daemon.c)
+ uds_validatelists();
+ // Check core mDNS lists
+ AuthRecord *rr;
for (rr = m->ResourceRecords; rr; rr=rr->next)
{
- if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
- LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
if (rr->resrec.name != &rr->namestorage)
- LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s",
+ LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
}
for (rr = m->DuplicateRecords; rr; rr=rr->next)
- if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
- LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ rr = m->NewLocalRecords;
+ if (rr)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ rr = m->CurrentRecord;
+ if (rr)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType);
+ DNSQuestion *q;
for (q = m->Questions; q; q=q->next)
- if (q->ThisQInterval == (mDNSs32)~0)
- LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q, q->ThisQInterval);
+ if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32)~0)
+ LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
+ CacheGroup *cg;
+ CacheRecord *cr;
+ mDNSu32 slot;
FORALL_CACHERECORDS(slot, cg, cr)
+ {
if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
- LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->resrec.RecordType);
+ LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType);
+ if (cr->CRActiveQuestion)
+ {
+ for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break;
+ if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr));
+ }
+ }
+ // Check core uDNS lists
+ udns_validatelists(m);
+
+ // Check platform-layer lists
+ NetworkInterfaceInfoOSX *i;
for (i = m->p->InterfaceList; i; i = i->next)
- if (!i->ifa_name)
- LogMsg("!!!! InterfaceList: %p is garbage !!!!", i);
+ if (i->next == (NetworkInterfaceInfoOSX *)~0 || !i->ifa_name || i->ifa_name == (char *)~0)
+ LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i, i->ifa_name);
+
+ ClientTunnel *t;
+ for (t = m->TunnelClients; t; t=t->next)
+ if (t->next == (ClientTunnel *)~0 || t->dstname.c[0] > 63)
+ LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]);
}
void *mallocL(char *msg, unsigned int size)
}
else
{
- LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
+ if (size > 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg, size, &mem[2]);
+ else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
mem[0] = 0xDEAD1234;
mem[1] = size;
- //bzero(&mem[2], size);
+ //mDNSPlatformMemZero(&mem[2], size);
memset(&mem[2], 0xFF, size);
validatelists(&mDNSStorage);
return(&mem[2]);
else
{
unsigned long *mem = ((unsigned long *)x) - 2;
- if (mem[0] != 0xDEAD1234)
- { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
- if (mem[1] > 24000)
- { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
- LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
- //bzero(mem, mem[1]+8);
+ if (mem[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
+ if (mem[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg, mem[1], &mem[2]);
+ else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
+ //mDNSPlatformMemZero(mem, mem[1]+8);
memset(mem, 0xFF, mem[1]+8);
validatelists(&mDNSStorage);
free(mem);
//*************************************************************************************************************
// Client Death Detection
+// This gets called after ALL constituent records of the Service Record Set have been deregistered
mDNSlocal void FreeServiceInstance(ServiceInstance *x)
{
ServiceRecordSet *s = &x->srs;
ExtraResourceRecord *e = x->srs.Extras, *tmp;
- while(e)
+ while (e)
{
e->r.RecordContext = e;
tmp = e;
}
if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage)
- freeL("TXT RData", s->RR_TXT.resrec.rdata);
+ freeL("TXT RData", s->RR_TXT.resrec.rdata);
if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes);
freeL("ServiceInstance", x);
while (qptr)
{
if (m && m != x)
- LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x);
- else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort, qptr->q.qname.c);
+ LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x);
+ else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort, qptr->q.qname.c);
mDNS_StopBrowse(&mDNSStorage, &qptr->q);
freePtr = qptr;
qptr = qptr->next;
DNSServiceResolver *x = *l;
*l = (*l)->next;
if (m && m != x)
- LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x);
- else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort, x->i.name.c);
+ LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x);
+ else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort, x->i.name.c);
mDNS_StopResolveService(&mDNSStorage, &x->q);
freeL("DNSServiceResolver", x);
return;
{
ServiceInstance *instance = si;
si = si->next;
- instance->autorename = mDNSfalse;
- if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x);
+ instance->renameonmemfree = mDNSfalse;
+ if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x);
else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs));
// If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
// the list, so we should go ahead and free the memory right now
if (mDNS_DeregisterService(&mDNSStorage, &instance->srs)) FreeServiceInstance(instance); // FreeServiceInstance invalidates pointer
}
- x->regs = NULL;
+ x->regs = NULL;
freeL("DNSServiceRegistration", x);
return;
}
while (b && b->ClientMachPort != c) b = b->next;
while (l && l->ClientMachPort != c) l = l->next;
while (r && r->ClientMachPort != c) r = r->next;
- if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg);
+
+ if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg);
else if (b)
- {
- for (qptr = b->qlist; qptr; qptr = qptr->next)
- LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg);
- }
- else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg);
+ {
+ for (qptr = b->qlist; qptr; qptr = qptr->next)
+ LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg);
+ }
+ else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg);
else if (r)
- {
- ServiceInstance *si;
- for (si = r->regs; si; si = si->next) LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg);
- }
- else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg);
+ {
+ ServiceInstance *si;
+ for (si = r->regs; si; si = si->next)
+ LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg);
+ }
+ else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg);
AbortClient(c, m);
}
mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info)
{
+ KQueueLock(&mDNSStorage);
mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg;
(void)unusedport; // Unused
(void)size; // Unused
/* Deallocate the send right that came in the dead name notification */
mach_port_destroy(mach_task_self(), deathMessage->not_port);
}
+ KQueueUnlock(&mDNSStorage, "Mach AbortClient");
}
mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m)
//*************************************************************************************************************
// Domain Enumeration
-mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
kern_return_t status;
- #pragma unused(m)
char buffer[MAX_ESCAPED_DOMAIN_NAME];
DNSServiceDomainEnumerationReplyResultType rt;
DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext;
+ (void)m; // Unused
debugf("DomainEnumFound: %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
if (answer->rrtype != kDNSType_PTR) return;
//*************************************************************************************************************
// Browse for services
-mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
(void)m; // Unused
DNSServiceBrowserResult **p = &browser->results;
while (*p) p = &(*p)->next;
*p = x;
+
+ LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
+ browser->ClientMachPort, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
}
mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d)
return err;
}
-mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add)
+mDNSexport void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add)
{
DNSServiceBrowser *ptr;
-
- debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next)
{
if (ptr->DefaultDomain)
{
DNSServiceBrowserQuestion *remove = *q;
*q = (*q)->next;
- if (remove->q.LongLived)
- {
- // give goodbyes for known answers. note that since events are sent to client via udns_execute(),
- // we don't need to worry about the question being cancelled mid-loop
- CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
- while (ka) { remove->q.QuestionCallback(&mDNSStorage, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
- }
- mDNS_StopBrowse(&mDNSStorage, &remove->q);
+ mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q);
freeL("DNSServiceBrowserQuestion", remove );
- return;
- }
+ return;
+ }
q = &(*q)->next;
}
LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
(void)unusedserver; // Unused
mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
- DNameListElem *SearchDomains = NULL, *sdPtr;
if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
{
// Start browser for an explicit domain
x->DefaultDomain = mDNSfalse;
- if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain"; goto badparam; }
+ if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain"; goto badparam; }
err = AddDomainToBrowser(x, &d);
if (err) { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
}
else
{
+ DNameListElem *sdPtr;
// Start browser on all domains
x->DefaultDomain = mDNStrue;
- SearchDomains = mDNSPlatformGetSearchDomainList();
- if (!SearchDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
- for (sdPtr = SearchDomains; sdPtr; sdPtr = sdPtr->next)
+ if (!AutoBrowseDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
+ for (sdPtr = AutoBrowseDomains; sdPtr; sdPtr = sdPtr->next)
{
err = AddDomainToBrowser(x, &sdPtr->name);
if (err)
// Succeeded: Wrap up and return
EnableDeathNotificationForClient(client, x);
- mDNS_FreeDNameList(SearchDomains);
return(mStatus_NoError);
badparam:
err = mStatus_BadParamErr;
fail:
LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err);
- if (SearchDomains) mDNS_FreeDNameList(SearchDomains);
return(err);
- }
+ }
//*************************************************************************************************************
// Resolve Service Info
if (query->info->TXTlen > sizeof(cstring)) return;
- bzero(&interface, sizeof(interface));
- bzero(&address, sizeof(address));
+ mDNSPlatformMemZero(&interface, sizeof(interface));
+ mDNSPlatformMemZero(&address, sizeof(address));
if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4)
{
sin6->sin6_family = AF_INET6;
sin6->sin6_flowinfo = 0;
sin6->sin6_port = 0;
- sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
+ sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
sin6->sin6_scope_id = ifx->scope_id;
}
sin6->sin6_family = AF_INET6;
sin6->sin6_port = query->info->port.NotAnInteger;
sin6->sin6_flowinfo = 0;
- sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6;
+ sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6;
sin6->sin6_scope_id = ifx ? ifx->scope_id : 0;
}
DNSServiceResolverList = x;
// Do the operation
- LogOperation("%5d: DNSServiceResolver(%##s) START", client, x->i.name.c);
+ LogOperation("%5d: DNSServiceResolve(%##s) START", client, x->i.name.c);
err = mDNS_StartResolveService(&mDNSStorage, &x->q, &x->i, FoundInstanceInfo, x);
if (err) { AbortClient(client, x); errormsg = "mDNS_StartResolveService"; goto fail; }
else if (result == mStatus_MemFree)
{
- if (si->autorename)
+ if (si->renameonmemfree) // We intentionally terminated registration so we could re-register with new name
{
debugf("RegCallback renaming %#s to %#s", si->name.c, m->nicelabel.c);
- si->autorename = mDNSfalse;
- si->name = m->nicelabel;
+ si->renameonmemfree = mDNSfalse;
+ si->name = m->nicelabel;
mDNS_RenameAndReregisterService(m, srs, &si->name);
}
else
DNSServiceRegistration *r;
for (r = DNSServiceRegistrationList; r; r = r->next)
{
- ServiceInstance *sp = r->regs, *prev = NULL;
- while (sp)
+ ServiceInstance **sp = &r->regs;
+ while (*sp)
{
- if (sp == si)
- {
- LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs->RR_SRV.resrec.name->c);
- if (prev) prev->next = sp->next;
- else r->regs = sp->next;
- break;
- }
- prev = sp;
- sp = sp->next;
+ if (*sp == si) { LogMsg("RegCallback: %##s Still in list; removing", srs->RR_SRV.resrec.name->c); *sp = (*sp)->next; break; }
+ sp = &(*sp)->next;
}
}
// END SANITY CHECK
si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize);
if (!si) return mStatus_NoMemoryErr;
- si->ClientMachPort = x->ClientMachPort;
- si->autorename = mDNSfalse;
- si->autoname = x->autoname;
- si->name = x->autoname ? mDNSStorage.nicelabel : x->name;
- si->domain = *domain;
+ si->ClientMachPort = x->ClientMachPort;
+ si->renameonmemfree = mDNSfalse;
+ si->autoname = x->autoname;
+ si->name = x->autoname ? mDNSStorage.nicelabel : x->name;
+ si->domain = *domain;
- err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL, x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si);
+ err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL,
+ x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si);
if (!err)
{
si->next = x->regs;
LogMsg("Error %d for registration of service in domain %##s", err, domain->c);
freeL("ServiceInstance", si);
}
- return err;
+ return err;
}
-mDNSexport void DefaultRegDomainChanged(const domainname *d, mDNSBool add)
+mDNSexport void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add)
{
DNSServiceRegistration *reg;
if (reg->DefaultDomain)
{
if (add)
- {
AddServiceInstance(reg, d);
- }
else
{
- ServiceInstance *si = reg->regs, *prev = NULL;
- while (si)
+ ServiceInstance **si = ®->regs;
+ while (*si)
{
- if (SameDomainName(&si->domain, d))
+ if (SameDomainName(&(*si)->domain, d))
{
- if (prev) prev->next = si->next;
- else reg->regs = si->next;
- if (mDNS_DeregisterService(&mDNSStorage, &si->srs))
- FreeServiceInstance(si); // only free memory synchronously on error
+ ServiceInstance *s = *si;
+ *si = (*si)->next;
+ if (mDNS_DeregisterService(&mDNSStorage, &s->srs)) FreeServiceInstance(s); // only free memory synchronously on error
break;
}
- prev = si;
- si = si->next;
+ si = &(*si)->next;
}
if (!si) debugf("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort); // normal if registration failed
- }
+ }
}
}
}
// Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
// a port number of zero. When two instances of the protected client are allowed to run on one
// machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
- if (port.NotAnInteger)
+ if (!mDNSIPPortIsZero(port))
{
int count = CountExistingRegistrations(&srv, port);
if (count)
// Allocate memory, and handle failure
DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x));
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
- bzero(x, sizeof(*x));
+ mDNSPlatformMemZero(x, sizeof(*x));
// Set up object, and link into list
x->ClientMachPort = client;
x->type = t;
x->port = port;
memcpy(x->txtinfo, txtinfo, 1024);
- x->txt_len = data_len;
+ x->txt_len = data_len;
x->NextRef = 0;
x->regs = NULL;
if (x->DefaultDomain)
{
- DNameListElem *ptr, *regdomains = mDNSPlatformGetRegDomainList();
- for (ptr = regdomains; ptr; ptr = ptr->next)
+ DNameListElem *ptr;
+ for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
AddServiceInstance(x, &ptr->name);
- mDNS_FreeDNameList(regdomains);
- }
+ }
// Succeeded: Wrap up and return
EnableDeathNotificationForClient(client, x);
return(err);
}
-mDNSlocal CFUserNotificationRef gNotification = NULL;
-mDNSlocal CFRunLoopSourceRef gNotificationRLS = NULL;
-mDNSlocal domainlabel gNotificationPrefHostLabel; // The prefs as they were the last time we saw them
-mDNSlocal domainlabel gNotificationPrefNiceLabel;
-mDNSlocal domainlabel gNotificationUserHostLabel; // The prefs as they were the last time the user changed them
-mDNSlocal domainlabel gNotificationUserNiceLabel;
-
-mDNSlocal void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
- {
- (void)responseFlags; // Unused
- if (userNotification != gNotification) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef");
- if (gNotificationRLS)
- {
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS, kCFRunLoopDefaultMode);
- CFRelease(gNotificationRLS);
- gNotificationRLS = NULL;
- CFRelease(gNotification);
- gNotification = NULL;
- }
- // By dismissing the alert, the user has conceptually acknowleged the rename.
- // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
- // If we get *another* conflict, the new alert should refer to the 'old'.
- // name as now being "computer-2.local", not "computer.local"
- gNotificationUserHostLabel = gNotificationPrefHostLabel;
- gNotificationUserNiceLabel = gNotificationPrefNiceLabel;
- }
-
-mDNSlocal void ShowNameConflictNotification(CFStringRef header, CFStringRef subtext)
- {
- CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!dictionary) return;
- CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
- CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
-
- CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
- if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
-
- if (gNotification) // If notification already on-screen, update it in place
- CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
- else // else, we need to create it
- {
- SInt32 error;
- gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
- if (!gNotification) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; }
- gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
- if (!gNotificationRLS) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
- CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS, kCFRunLoopDefaultMode);
- }
-
- CFRelease(dictionary);
- }
-
-// This updates either the text of the field currently labelled "Local Hostname",
-// or the text of the field currently labelled "Computer Name"
-// in the Sharing Prefs Control Panel
-mDNSlocal void RecordUpdatedName(const mDNS *const m, const domainlabel *const olddl, const domainlabel *const newdl,
- const char *const msg, const char *const suffix, const CFStringRef subtext)
- {
- char oldname[MAX_DOMAIN_LABEL+1];
- char newname[MAX_DOMAIN_LABEL+1];
- ConvertDomainLabelToCString_unescaped(olddl, oldname);
- ConvertDomainLabelToCString_unescaped(newdl, newname);
- const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
- const CFStringRef cfnewname = CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8);
- const CFStringRef f1 = CFStringCreateWithCString(NULL, " “%@%s” ", kCFStringEncodingUTF8);
- const CFStringRef f2 = CFStringCreateWithCString(NULL, " “%@%s” ", kCFStringEncodingUTF8);
- const SCPreferencesRef session = SCPreferencesCreate(NULL, CFSTR("mDNSResponder"), NULL);
- if (!cfoldname || !cfnewname || !f1 || !f2 || !session || !SCPreferencesLock(session, 0)) // If we can't get the lock don't wait
- LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session");
- else
- {
- const CFStringRef s0 = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
- const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, f1, cfoldname, suffix);
- const CFStringRef s2 = CFStringCreateWithFormat(NULL, NULL, f2, cfnewname, suffix);
- // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each
- // element of the array individually for us, and then concatenate the results to make the final message.
- // This lets us have the relevant bits localized, but not the literal names, which should not be translated.
- // On Panther this does not work, so we just build the string directly, and it will not be translated.
- const CFMutableStringRef alertHeader =
- (OSXVers < 8) ? CFStringCreateMutable(NULL, 0) : (CFMutableStringRef)CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- Boolean result;
- if (newdl == &gNotificationPrefHostLabel) result = SCPreferencesSetLocalHostName(session, cfnewname);
- else result = SCPreferencesSetComputerName(session, cfnewname, kCFStringEncodingUTF8);
- if (!result || !SCPreferencesCommitChanges(session) || !SCPreferencesApplyChanges(session) || !s0 || !s1 || !s2 || !alertHeader)
- LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences");
- else if (m->p->NotifyUser)
- {
- uid_t uid;
- gid_t gid;
- CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
- if (userName)
- {
- CFRelease(userName);
- typedef void CFStringAppendFN(CFMutableStringRef theString, CFStringRef appendedString);
- CFStringAppendFN *const append = (OSXVers < 8) ? &CFStringAppend : (CFStringAppendFN*)&CFArrayAppendValue;
- append(alertHeader, s0);
- append(alertHeader, s1);
- append(alertHeader, CFSTR("is already in use on this network."));
- append(alertHeader, CFSTR(" "));
- append(alertHeader, CFSTR("The name has been changed to"));
- append(alertHeader, s2);
- append(alertHeader, CFSTR("automatically."));
- ShowNameConflictNotification(alertHeader, subtext);
- }
- }
- if (s0) CFRelease(s0);
- if (s1) CFRelease(s1);
- if (s2) CFRelease(s2);
- if (alertHeader) CFRelease(alertHeader);
- SCPreferencesUnlock(session);
- }
- if (cfoldname) CFRelease(cfoldname);
- if (cfnewname) CFRelease(cfnewname);
- if (f1) CFRelease(f1);
- if (f2) CFRelease(f2);
- if (session) CFRelease(session);
- }
-
mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
{
(void)m; // Unused
- if (result == mStatus_NoError)
+ if (result == mStatus_NoError)
{
+ if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
+ LogOperation("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
// One second pause in case we get a Computer Name update too -- don't want to alert the user twice
RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond);
}
- else if (result == mStatus_ConfigChanged)
+ else if (result == mStatus_NameConflict)
{
- // If the user-specified hostlabel from System Configuration has changed since the last time
- // we saw it, and *we* didn't change it, then that implies that the user has changed it,
- // so we auto-dismiss the name conflict alert.
- if (!SameDomainLabel(m->p->userhostlabel.c, gNotificationPrefHostLabel.c) ||
- !SameDomainLabel(m->p->usernicelabel.c, gNotificationPrefNiceLabel.c))
+ LogOperation("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c);
+ if (!m->p->HostNameConflict) m->p->HostNameConflict = NonZeroTime(m->timenow);
+ else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond)
{
- gNotificationUserHostLabel = gNotificationPrefHostLabel = m->p->userhostlabel;
- gNotificationUserNiceLabel = gNotificationPrefNiceLabel = m->p->usernicelabel;
- // If we're showing a name conflict notification, and the user has manually edited
- // the name to remedy the conflict, we should now remove the notification window.
- if (gNotificationRLS) CFUserNotificationCancel(gNotification);
+ // Tell the helper we've given up
+ mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, NULL);
}
+ }
+ else if (result == mStatus_GrowCache)
+ {
+ // Allocate another chunk of cache storage
+ CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE);
+ //LogOperation("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
+ if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
+ }
+ else if (result == mStatus_ConfigChanged)
+ {
+ // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed.
+ mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+ mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
+ // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
DNSServiceRegistration *r;
for (r = DNSServiceRegistrationList; r; r=r->next)
if (r->autoname)
ServiceInstance *si;
for (si = r->regs; si; si = si->next)
{
- if (!SameDomainLabel(si->name.c, m->nicelabel.c))
+ if (!SameDomainLabelCS(si->name.c, m->nicelabel.c))
{
debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c);
- si->autorename = mDNStrue;
+ si->renameonmemfree = mDNStrue;
if (mDNS_DeregisterService(m, &si->srs)) // If service deregistered already, we can re-register immediately
RegCallback(m, &si->srs, mStatus_MemFree);
}
}
}
- udsserver_handle_configchange();
- }
- else if (result == mStatus_GrowCache)
- {
- // Allocate another chunk of cache storage
- CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE);
- if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
+
+ // Then we call into the UDS daemon code, to let it do the same
+ udsserver_handle_configchange(m);
}
}
id = x->NextRef++;
*reference = (natural_t)id;
for (si = x->regs; si; si = si->next)
- {
+ {
// Allocate memory, and handle failure
ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
return mStatus_NoError;
fail:
- LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x->name.c, type, data_len, errormsg, err);
+ LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x ? x->name.c : (mDNSu8*)"\x8""«NULL»", type, data_len, errormsg, err);
return mStatus_UnknownErr;
}
// Check client parameter
mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
- domainname *name = (domainname *)"";
+ const domainname *name = (const domainname *)"";
name = srs->RR_SRV.resrec.name;
// Check client parameter
mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
- domainname *name = (domainname *)"";
+ const domainname *name = (const domainname *)"";
ServiceInstance *si;
(void)unusedserver; // unused
mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client)
{
- domainname *name = srs->RR_SRV.resrec.name;
+ const domainname *const name = srs->RR_SRV.resrec.name;
mStatus err = mStatus_NoError;
// Do the operation
(void)size; // Unused
(void)info; // Unused
+ KQueueLock(&mDNSStorage);
+
/* allocate a reply buffer */
reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0);
* user or the remote one, we pretend it's ok.
*/
CFAllocatorDeallocate(NULL, reply);
- return;
+ goto done;
}
/*
if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
mach_msg_destroy(&reply->Head);
CFAllocatorDeallocate(NULL, reply);
- return;
+ goto done;
}
/*
}
CFAllocatorDeallocate(NULL, reply);
+
+done:
+ KQueueUnlock(&mDNSStorage, "Mach client event");
}
mDNSlocal kern_return_t registerBootstrapService()
mDNSlocal void ExitCallback(int signal)
{
+ (void)signal; // Unused
LogMsgIdent(mDNSResponderVersionString, "stopping");
debugf("ExitCallback");
- if (!mDNS_DebugMode && !started_via_launchdaemon && signal != SIGHUP)
+ if (!mDNS_DebugMode && !started_via_launchdaemon)
destroyBootstrapService();
debugf("ExitCallback: Aborting MIG clients");
debugf("ExitCallback: mDNS_Close");
mDNS_Close(&mDNSStorage);
- if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed");
+ if (udsserver_exit(launchd_fd) < 0) LogMsg("ExitCallback: udsserver_exit failed");
exit(0);
}
if (mach_msg_send(&header) != MACH_MSG_SUCCESS)
{
LogMsg("HandleSIG %d: mach_msg_send failed", signal);
- if (signal == SIGHUP || signal == SIGTERM || signal == SIGINT) exit(-1);
+ if (signal == SIGTERM || signal == SIGINT) exit(-1);
}
}
DNSServiceResolver *l;
DNSServiceRegistration *r;
NetworkInterfaceInfoOSX *i;
+ DNSServer *s;
LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
udsserver_info(&mDNSStorage);
- for (e = DNSServiceDomainEnumerationList; e; e=e->next)
- LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e->ClientMachPort, e->dom.qname.c);
+ LogMsgNoIdent("--------- Mach Clients ---------");
+ if (!DNSServiceDomainEnumerationList && !DNSServiceBrowserList && !DNSServiceResolverList && !DNSServiceRegistrationList)
+ LogMsgNoIdent("<None>");
+ else
+ {
+ for (e = DNSServiceDomainEnumerationList; e; e=e->next)
+ LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e->ClientMachPort, e->dom.qname.c);
+
+ for (b = DNSServiceBrowserList; b; b=b->next)
+ {
+ DNSServiceBrowserQuestion *qptr;
+ for (qptr = b->qlist; qptr; qptr = qptr->next)
+ LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b->ClientMachPort, qptr->q.qname.c);
+ }
+ for (l = DNSServiceResolverList; l; l=l->next)
+ LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l->ClientMachPort, l->i.name.c);
+
+ for (r = DNSServiceRegistrationList; r; r=r->next)
+ {
+ ServiceInstance *si;
+ for (si = r->regs; si; si = si->next)
+ LogMsgNoIdent("%5d: Mach ServiceInstance %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name->c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port));
+ }
+ }
- for (b = DNSServiceBrowserList; b; b=b->next)
+ LogMsgNoIdent("----- KQSocketEventSources -----");
+ if (!gEventSources) LogMsgNoIdent("<None>");
+ else
{
- DNSServiceBrowserQuestion *qptr;
- for (qptr = b->qlist; qptr; qptr = qptr->next)
- LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b->ClientMachPort, qptr->q.qname.c);
+ KQSocketEventSource *k;
+ for (k = gEventSources; k; k=k->next)
+ LogMsgNoIdent("%3d %s", k->fd, k->kqs.KQtask);
}
- for (l = DNSServiceResolverList; l; l=l->next)
- LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l->ClientMachPort, l->i.name.c);
- for (r = DNSServiceRegistrationList; r; r=r->next)
+ LogMsgNoIdent("------ Network Interfaces ------");
+ if (!mDNSStorage.p->InterfaceList) LogMsgNoIdent("<None>");
+ else
{
- ServiceInstance *si;
- for (si = r->regs; si; si = si->next)
- LogMsgNoIdent("%5d: Mach ServiceInstance %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name->c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port));
+ for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+ {
+ if (!i->Exists)
+ LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %#a dormant for %d seconds",
+ i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
+ &i->ifinfo.ip, utc - i->LastSeen);
+ else
+ LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %-15.4a %s InterfaceID %p %s %s %#a",
+ i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
+ i->ifinfo.InterfaceActive ? "Active" : " ",
+ i->ifinfo.IPv4Available ? "v4" : " ",
+ i->ifinfo.IPv4Available ? (mDNSv4Addr*)&i->ifa_v4addr : &zerov4Addr,
+ i->ifinfo.IPv6Available ? "v6" : " ",
+ i->ifinfo.InterfaceID,
+ i->ifinfo.Advertise ? "Adv" : " ",
+ i->ifinfo.McastTxRx ? "TxRx" : " ",
+ &i->ifinfo.ip);
+ }
}
- for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+ LogMsgNoIdent("--------- DNS Servers ----------");
+ if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
+ else
{
- if (!i->Exists)
- LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
- i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID, utc - i->LastSeen);
- else
- LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
- i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
- i->ifinfo.InterfaceActive ? "Active" : " ",
- i->ifinfo.IPv4Available ? "v4" : " ", i->ss.sktv4,
- i->ifinfo.IPv6Available ? "v6" : " ", i->ss.sktv6,
- i->ifinfo.InterfaceID,
- i->ifinfo.Advertise ? "Adv" : " ",
- i->ifinfo.McastTxRx ? "TxRx" : " ",
- &i->ifinfo.ip);
+ for (s = mDNSStorage.DNSServers; s; s = s->next)
+ {
+ NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)s->interface;
+ LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %s",
+ s->domain.c, ifx ? ifx->ifa_name : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
+ s->teststate == DNSServer_Untested ? "(Untested)" :
+ s->teststate == DNSServer_Passed ? "" :
+ s->teststate == DNSServer_Failed ? "(Failed)" :
+ s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)");
+ }
}
+ mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
+ LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+
LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----");
}
(void)port; // Unused
(void)size; // Unused
(void)info; // Unused
- mach_msg_header_t *m = (mach_msg_header_t *)msg;
- switch(m->msgh_id)
+ mach_msg_header_t *msg_header = (mach_msg_header_t *)msg;
+ KQueueLock(&mDNSStorage);
+ switch(msg_header->msgh_id)
{
- case SIGHUP:
- case SIGINT:
- case SIGTERM: ExitCallback(m->msgh_id); break;
+ case SIGHUP: {
+ mDNS *m = &mDNSStorage;
+ mDNSu32 slot;
+ CacheGroup *cg;
+ CacheRecord *rr;
+ LogMsg("SIGHUP: Purge cache");
+ FORALL_CACHERECORDS(slot, cg, rr) mDNS_PurgeCacheResourceRecord(m, rr);
+ } break;
+ case SIGINT:
+ case SIGTERM: ExitCallback(msg_header->msgh_id); break;
case SIGINFO: INFOCallback(); break;
case SIGUSR1: LogMsg("SIGUSR1: Simulate Network Configuration Change Event");
mDNSMacOSXNetworkChanged(&mDNSStorage); break;
- default: LogMsg("SignalCallback: Unknown signal %d", m->msgh_id); break;
+ case SIGUSR2: SigLogLevel(); break;
+ default: LogMsg("SignalCallback: Unknown signal %d", msg_header->msgh_id); break;
}
+ KQueueUnlock(&mDNSStorage, "Unix Signal");
}
// On 10.2 the MachServerName is DNSServiceDiscoveryServer
mDNSlocal kern_return_t mDNSDaemonInitialize(void)
{
mStatus err;
+ CFMachPortRef s_port;
+
+ // If launchd already created our Mach port for us, then use that, else we create a new one of our own
+ if (m_port != MACH_PORT_NULL)
+ s_port = CFMachPortCreateWithPort(NULL, m_port, DNSserverCallback, NULL, NULL);
+ else
+ {
+ s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
+ m_port = CFMachPortGetPort(s_port);
+ char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
+ kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port);
+
+ if (status)
+ {
+ if (status == 1103)
+ LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
+ else
+ LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
+ return(status);
+ }
+ }
+
CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
- CFMachPortRef s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
CFMachPortRef i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
- mach_port_t m_port = CFMachPortGetPort(s_port);
- char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
- kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port);
CFRunLoopSourceRef d_rls = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
CFRunLoopSourceRef s_rls = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
CFRunLoopSourceRef i_rls = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
- if (status)
- {
- if (status == 1103)
- LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running");
- else
- LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status);
- return(status);
- }
-
err = mDNS_Init(&mDNSStorage, &PlatformStorage,
rrcachestorage, RR_CACHE_SIZE,
mDNS_Init_AdvertiseLocalAddresses,
if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); }
- gNotificationUserHostLabel = gNotificationPrefHostLabel = PlatformStorage.userhostlabel;
- gNotificationUserNiceLabel = gNotificationPrefNiceLabel = PlatformStorage.usernicelabel;
-
client_death_port = CFMachPortGetPort(d_port);
- signal_port = CFMachPortGetPort(i_port);
+ signal_port = CFMachPortGetPort(i_port);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls, kCFRunLoopDefaultMode);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls, kCFRunLoopDefaultMode);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls, kCFRunLoopDefaultMode);
+ CFRunLoop = CFRunLoopGetCurrent();
+ CFRunLoopAddSource(CFRunLoop, d_rls, kCFRunLoopDefaultMode);
+ CFRunLoopAddSource(CFRunLoop, s_rls, kCFRunLoopDefaultMode);
+ CFRunLoopAddSource(CFRunLoop, i_rls, kCFRunLoopDefaultMode);
CFRelease(d_rls);
CFRelease(s_rls);
CFRelease(i_rls);
{
if (m->p->NotifyUser - now < 0)
{
- if (!SameDomainLabel(m->p->usernicelabel.c, m->nicelabel.c))
+ if (!SameDomainLabelCS(m->p->usernicelabel.c, m->nicelabel.c))
{
- LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
- gNotificationPrefNiceLabel = m->p->usernicelabel = m->nicelabel;
- RecordUpdatedName(m, &gNotificationUserNiceLabel, &gNotificationPrefNiceLabel, "The name of your computer", "",
- CFSTR("To change the name of your computer, open System Preferences and click Sharing. "
- "Then type the name in the Computer Name field."));
- // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts
- m->p->NotifyUser = 0;
+ LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
+ mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+ m->p->usernicelabel = m->nicelabel;
}
- if (!SameDomainLabel(m->p->userhostlabel.c, m->hostlabel.c))
+ if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
{
- LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
- gNotificationPrefHostLabel = m->p->userhostlabel = m->hostlabel;
- RecordUpdatedName(m, &gNotificationUserHostLabel, &gNotificationPrefHostLabel, "This computer’s local hostname", ".local",
- CFSTR("To change the local hostname, open System Preferences and click Sharing. "
- "Then click Edit and type the name in the Local Hostname field."));
+ LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
+ mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
+ m->p->HostNameConflict = 0; // Clear our indicator, now name change has been successful
+ m->p->userhostlabel = m->hostlabel;
}
m->p->NotifyUser = 0;
}
LogMsg("Task Scheduling Error: Continuously busy for more than a second");
+ // NOTE: To accurately diagnose *why* we're busy, the debugging code here to show needs to mirror the logic in GetNextScheduledEvent
+
if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
LogMsg("Task Scheduling Error: m->SuppressSending %d", m->timenow - m->SuppressSending);
#ifndef UNICAST_DISABLED
- if (m->timenow - m->uDNS_info.nextevent >= 0)
- LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d", m->timenow - m->uDNS_info.nextevent);
+ if (m->timenow - m->NextuDNSEvent >= 0)
+ LogMsg("Task Scheduling Error: NextuDNSEvent %d", m->timenow - m->NextuDNSEvent);
#endif
if (m->timenow - m->NextCacheCheck >= 0)
LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck);
LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m->timenow - m->NextScheduledProbe);
if (m->timenow - m->NextScheduledResponse >= 0)
LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
+ if (m->timenow - m->NextScheduledNATOp >= 0)
+ LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d", m->timenow - m->NextScheduledNATOp);
mDNS_Unlock(&mDNSStorage);
}
+mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context)
+ {
+ // Read all of the bytes so we won't wake again.
+ char buffer[100];
+ ssize_t read = sizeof(buffer);
+ while (read > 0) read = recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT);
+ }
+
+mDNSlocal void * KQueueLoop(void *m_param)
+ {
+ mDNS *m = m_param;
+ int numevents = 0;
+
+#if USE_SELECT_WITH_KQUEUEFD
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ const int multiplier = 1000000 / mDNSPlatformOneSecond;
+#else
+ const int multiplier = 1000000000 / mDNSPlatformOneSecond;
+#endif
+
+ pthread_mutex_lock(&PlatformStorage.BigMutex);
+ LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
+
+ // This is the main work loop:
+ // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
+ // (2) Then we make sure we've delivered all waiting browse messages to our clients
+ // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
+ // (4) On wakeup we first process *all* events
+ // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
+ for ( ; ; )
+ {
+ #define kEventsToReadAtOnce 1
+ struct kevent new_events[kEventsToReadAtOnce];
+
+ // Run mDNS_Execute to find out the time we next need to wake up
+ mDNSs32 start = mDNSPlatformRawTime();
+ mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+ mDNSs32 end = mDNSPlatformRawTime();
+ if (end - start >= WatchDogReportingThreshold)
+ LogOperation("WARNING: Idle task took %dms to complete", end - start);
+
+ // Convert absolute wakeup time to a relative time from now
+ mDNSs32 ticks = nextTimerEvent - mDNS_TimeNow(m);
+ if (ticks < 1) ticks = 1;
+
+ static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins
+ if (ticks > 1)
+ RepeatedBusy = 0;
+ else
+ {
+ ticks = 1;
+ if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
+ }
+
+ verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents, ticks);
+ numevents = 0;
+
+ // Release the lock, and sleep until:
+ // 1. Something interesting happens like a packet arriving, or
+ // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
+ // 3. The timeout expires
+ pthread_mutex_unlock(&PlatformStorage.BigMutex);
+
+#if USE_SELECT_WITH_KQUEUEFD
+ struct timeval timeout;
+ timeout.tv_sec = ticks / mDNSPlatformOneSecond;
+ timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * multiplier;
+ FD_SET(KQueueFD, &readfds);
+ if (select(KQueueFD+1, &readfds, NULL, NULL, &timeout) < 0)
+ { LogMsg("select(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); }
+#else
+ struct timespec timeout;
+ timeout.tv_sec = ticks / mDNSPlatformOneSecond;
+ timeout.tv_nsec = (ticks % mDNSPlatformOneSecond) * multiplier;
+ // In my opinion, you ought to be able to call kevent() with nevents set to zero,
+ // and have it work similarly to the way it does with nevents non-zero --
+ // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
+ // In fact, what happens if you do this is that it just returns immediately. So, we have
+ // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
+ if (kevent(KQueueFD, NULL, 0, new_events, 1, &timeout) < 0)
+ { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); }
+#endif
+
+ pthread_mutex_lock(&PlatformStorage.BigMutex);
+ // We have to ignore the event we may have been told about above, because that
+ // was done without holding the lock, and between the time we woke up and the
+ // time we reclaimed the lock the other thread could have done something that
+ // makes the event no longer valid. Now we have the lock, we call kevent again
+ // and this time we can safely process the events it tells us about.
+
+ static const struct timespec zero_timeout = { 0, 0 };
+ int events_found;
+ while ((events_found = kevent(KQueueFD, NULL, 0, new_events, kEventsToReadAtOnce, &zero_timeout)) != 0)
+ {
+ if (events_found > kEventsToReadAtOnce || (events_found < 0 && errno != EINTR))
+ {
+ // Not sure what to do here, our kqueue has failed us - this isn't ideal
+ LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno, strerror(errno));
+ exit(errno);
+ }
+
+ numevents += events_found;
+
+ int i;
+ for (i = 0; i < events_found; i++)
+ {
+ const KQueueEntry *const kqentry = new_events[i].udata;
+ mDNSs32 start = mDNSPlatformRawTime();
+#if LogAllOperations || MDNS_DEBUGMSGS
+ const char *const KQtask = kqentry->KQtask; // Grab a copy in case KQcallback deletes the task
+#endif
+ kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext);
+ mDNSs32 end = mDNSPlatformRawTime();
+ if (end - start >= WatchDogReportingThreshold)
+ LogOperation("WARNING: %s took %dms to complete", KQtask, end - start);
+ }
+ }
+ }
+
+ return NULL;
+ }
+
+mDNSlocal void LaunchdCheckin(void)
+ {
+ launch_data_t msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+ launch_data_t resp = launch_msg(msg);
+ launch_data_free(msg);
+ if (!resp) { LogMsg("launch_msg returned NULL"); return; }
+
+ if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO)
+ {
+ int err = launch_data_get_errno(resp);
+ // When running on Tiger with "ServiceIPC = false", we get "err == EACCES" to tell us there's no launchdata to fetch
+ if (err != EACCES) LogMsg("launch_msg returned %d", err);
+ else LogOperation("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err);
+ }
+ else
+ {
+ launch_data_t skts = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);
+ if (!skts) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL");
+ else
+ {
+ launch_data_t skt = launch_data_dict_lookup(skts, "Listeners");
+ if (!skt) LogMsg("launch_data_dict_lookup Listeners returned NULL");
+ else
+ {
+ launch_data_t s = launch_data_array_get_index(skt, 0);
+ if (!s) LogMsg("launch_data_array_get_index(skt, 0) returned NULL");
+ else
+ {
+ launchd_fd = launch_data_get_fd(s);
+ LogOperation("Launchd Unix Domain Socket: %d", launchd_fd);
+ // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here
+ chmod(MDNS_UDS_SERVERPATH, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
+ }
+ }
+ }
+
+ launch_data_t ports = launch_data_dict_lookup(resp, "MachServices");
+ if (!ports) LogMsg("launch_data_dict_lookup MachServices returned NULL");
+ else
+ {
+ launch_data_t p = launch_data_dict_lookup(ports, "com.apple.mDNSResponder");
+ if (!p) LogOperation("launch_data_array_get_index(ports, 0) returned NULL");
+ else
+ {
+ m_port = launch_data_get_fd(p);
+ LogOperation("Launchd Mach Port: %d", m_port);
+ if (m_port == ~0U) m_port = MACH_PORT_NULL;
+ }
+ }
+ }
+ launch_data_free(resp);
+ }
+
+mDNSlocal void DropPrivileges(void)
+ {
+ static const char login[] = "_mdnsresponder";
+ struct passwd *pwd = getpwnam(login);
+ if (NULL == pwd)
+ LogMsg("Could not find account name \"%s\". Running as root.", login);
+ else
+ {
+ uid_t uid = pwd->pw_uid;
+ gid_t gid = pwd->pw_gid;
+
+ LogMsg("Started as root. Switching to userid \"%s\".", login);
+
+ if (unlink(MDNS_UDS_SERVERPATH) < 0 && errno != ENOENT) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", MDNS_UDS_SERVERPATH, errno, strerror(errno));
+ else
+ {
+ static char path[] = "/var/run/mdns/mDNSResponder";
+ char *p = strrchr(path, '/');
+ *p = '\0';
+ if (mkdir(path, 0755) < 0 && errno != EEXIST) LogMsg("DropPrivileges: Could not create directory \"%s\": (%d) %s", path, errno, strerror(errno));
+ else if (chown(path, uid, gid) < 0) LogMsg("DropPrivileges: Could not chown directory \"%s\": (%d) %s", path, errno, strerror(errno));
+ else
+ {
+ *p = '/';
+ if (unlink(path) < 0 && errno != ENOENT) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", path, errno, strerror(errno));
+ else if (symlink(path, MDNS_UDS_SERVERPATH) < 0) LogMsg("DropPrivileges: Could not symlink \"%s\" -> \"%s\": (%d) %s", MDNS_UDS_SERVERPATH, path, errno, strerror(errno));
+ else LogOperation("DropPrivileges: Created subdirectory and symlink");
+ }
+ }
+
+ if (0 != initgroups(login, gid)) LogMsg("initgroups(\"%s\", %lu) failed. Continuing.", login, (unsigned long)gid);
+ if (0 != setgid(gid)) LogMsg("setgid(%lu) failed. Continuing with group %lu privileges.", (unsigned long)getegid());
+ if (0 != setuid(uid)) LogMsg("setuid(%lu) failed. Continuing as root after all.", (unsigned long)uid);
+ }
+ }
+
+extern int sandbox_init(const char *profile, uint64_t flags, char **errorbuf) __attribute__((weak_import));
+
mDNSexport int main(int argc, char **argv)
{
int i;
kern_return_t status;
+ pthread_t KQueueThread;
+
+ LogMsgIdent(mDNSResponderVersionString, "starting");
+
+ if (0 == geteuid()) DropPrivileges();
for (i=1; i<argc; i++)
{
- if (!strcmp(argv[i], "-d")) mDNS_DebugMode = mDNStrue;
- if (!strcmp(argv[i], "-launchdaemon")) started_via_launchdaemon = mDNStrue;
+ if (!strcasecmp(argv[i], "-d" )) mDNS_DebugMode = mDNStrue;
+ if (!strcasecmp(argv[i], "-launchd" )) started_via_launchdaemon = mDNStrue;
+ if (!strcasecmp(argv[i], "-launchdaemon")) started_via_launchdaemon = mDNStrue;
}
- signal(SIGHUP, HandleSIG); // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
+ signal(SIGHUP, HandleSIG); // (Debugging) Purge the cache to check for cache handling bugs
signal(SIGINT, HandleSIG); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
signal(SIGPIPE, SIG_IGN ); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
signal(SIGTERM, HandleSIG); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
signal(SIGINFO, HandleSIG); // (Debugging) Write state snapshot to syslog
signal(SIGUSR1, HandleSIG); // (Debugging) Simulate network change notification from System Configuration Framework
+ signal(SIGUSR2, HandleSIG); // (Debugging) Change log level
+
+ mDNSStorage.p = &PlatformStorage; // Make sure mDNSStorage.p is set up, because validatelists uses it
+ LaunchdCheckin();
// Register the server with mach_init for automatic restart only during normal (non-debug) mode
if (!mDNS_DebugMode && !started_via_launchdaemon)
}
}
- // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
- // The sooner we do this, the faster the machine will boot.
- status = udsserver_init();
- if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
+ // Create the kqueue, mutex and thread to support KQSockets
+ KQueueFD = kqueue();
+ if (KQueueFD == -1) { LogMsg("kqueue() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
- // First do the all the initialization we need root privilege for, before we change to user "nobody"
- LogMsgIdent(mDNSResponderVersionString, "starting");
- OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
- status = mDNSDaemonInitialize();
-
-#if CAN_UPDATE_DYNAMIC_STORE_WITHOUT_BEING_ROOT
- // Now that we're finished with anything privileged, switch over to running as "nobody"
- const struct passwd *pw = getpwnam("nobody");
- if (pw != NULL)
- setuid(pw->pw_uid);
+ i = pthread_mutex_init(&PlatformStorage.BigMutex, NULL);
+ if (i == -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+
+ int fdpair[2] = {0, 0};
+ i = socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair);
+ if (i == -1) { LogMsg("socketpair() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+
+ // Socket pair returned us two identical sockets connected to each other
+ // We will use the first socket to send the second socket. The second socket
+ // will be added to the kqueue so it will wake when data is sent.
+ static const KQueueEntry wakeKQEntry = { KQWokenFlushBytes, NULL, "kqueue wakeup after CFRunLoop event" };
+ PlatformStorage.WakeKQueueLoopFD = fdpair[0];
+ KQueueSet(fdpair[1], EV_ADD, EVFILT_READ, &wakeKQEntry);
+
+ // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
+#if MDNS_NO_SANDBOX
+ LogMsg("Note: Compiled without Apple Sandbox support");
+#else
+ if (!sandbox_init)
+ LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
else
- setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database
+ {
+ char *sandbox_msg;
+ int sandbox_err = sandbox_init("mDNSResponder", SANDBOX_NAMED, &sandbox_msg);
+ if (sandbox_err) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg); sandbox_free_error(sandbox_msg); }
+ else LogOperation("Now running under Apple Sandbox restrictions");
+ }
#endif
+ OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
+ status = mDNSDaemonInitialize();
+ if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; }
+ status = udsserver_init(launchd_fd);
+ if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
+
+ // Start the kqueue thread
+ i = pthread_create(&KQueueThread, NULL, KQueueLoop, &mDNSStorage);
+ if (i == -1) { LogMsg("pthread_create() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+
if (status == 0)
{
- LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
- int numevents = 0;
- int RunLoopStatus = kCFRunLoopRunTimedOut;
-
- // This is the main work loop:
- // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
- // (2) Then we make sure we've delivered all waiting browse messages to our clients
- // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
- // (4) On wakeup we first process *all* events
- // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
- while (RunLoopStatus == kCFRunLoopRunTimedOut)
- {
- // 1. Before going into a blocking wait call and letting our process to go sleep,
- // call mDNSDaemonIdle to allow any deferred work to be completed.
- mDNSs32 nextevent = mDNSDaemonIdle(&mDNSStorage);
- nextevent = udsserver_idle(nextevent);
-
- // 2. Work out how long we expect to sleep before the next scheduled task
- mDNSs32 ticks = nextevent - mDNS_TimeNow(&mDNSStorage);
- static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins
- if (ticks > 1)
- RepeatedBusy = 0;
- else
- {
- ticks = 1;
- if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
- }
- CFAbsoluteTime interval = (CFAbsoluteTime)ticks / (CFAbsoluteTime)mDNSPlatformOneSecond;
-
- // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until
- // (a) our next wakeup time, or (b) an event occurs.
- // The 'true' parameter makes it return after handling any event that occurs
- // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again
- verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents, ticks);
- numevents = 0;
- RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, true);
-
- // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle()
- while (RunLoopStatus == kCFRunLoopRunHandledSource)
- {
- numevents++;
- RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true);
- }
- }
-
+ CFRunLoopRun();
LogMsg("ERROR: CFRunLoopRun Exiting.");
mDNS_Close(&mDNSStorage);
}
return(status);
}
-// uds_daemon.c support routines /////////////////////////////////////////////
-
-// We keep a list of client-supplied event sources in PosixEventSource records
-struct CFSocketEventSource
- {
- udsEventCallback Callback;
- void *Context;
- int fd;
- struct CFSocketEventSource *Next;
- CFSocketRef cfs;
- CFRunLoopSourceRef RLS;
- };
-typedef struct CFSocketEventSource CFSocketEventSource;
-
-static GenLinkedList gEventSources; // linked list of CFSocketEventSource's
-
-mDNSlocal void cf_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i)
- // Called by CFSocket when data appears on socket
- {
- (void)s; // Unused
- (void)t; // Unused
- (void)dr; // Unused
- (void)c; // Unused
- CFSocketEventSource *source = (CFSocketEventSource*) i;
- source->Callback(source->Context);
- }
+// uds_daemon.c support routines /////////////////////////////////////////////
+// Arrange things so that callback is called with context when data appears on fd
mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
- // Arrange things so that callback is called with context when data appears on fd
{
- CFSocketEventSource *newSource;
- CFSocketContext cfContext = { 0, NULL, NULL, NULL, NULL };
-
- if (gEventSources.LinkOffset == 0)
- InitLinkedList(&gEventSources, offsetof(CFSocketEventSource, Next));
+ KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource);
+ if (!newSource) return mStatus_NoMemoryErr;
- if (fd >= FD_SETSIZE || fd < 0)
- return mStatus_UnsupportedErr;
- if (callback == NULL)
- return mStatus_BadParamErr;
-
- newSource = (CFSocketEventSource*) calloc(1, sizeof *newSource);
- if (NULL == newSource)
- return mStatus_NoMemoryErr;
-
- newSource->Callback = callback;
- newSource->Context = context;
+ mDNSPlatformMemZero(newSource, sizeof(*newSource));
newSource->fd = fd;
+ newSource->kqs.KQcallback = callback;
+ newSource->kqs.KQcontext = context;
+ newSource->kqs.KQtask = "UDS client";
- cfContext.info = newSource;
- if ( NULL != (newSource->cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack,
- cf_callback, &cfContext)) &&
- NULL != (newSource->RLS = CFSocketCreateRunLoopSource(kCFAllocatorDefault, newSource->cfs, 0)))
+ if (KQueueSet(fd, EV_ADD, EVFILT_READ, &newSource->kqs) == 0)
{
- CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource->RLS, kCFRunLoopDefaultMode);
- AddToTail(&gEventSources, newSource);
+ KQSocketEventSource **p = &gEventSources;
+ while (*p) p = &(*p)->next;
+ *p = newSource;
+ return mStatus_NoError;
}
else
{
- if (newSource->cfs)
- {
- CFSocketInvalidate(newSource->cfs); // Note: Also closes the underlying socket
- CFRelease(newSource->cfs);
- }
+ close(fd);
+ free(newSource);
return mStatus_NoMemoryErr;
}
-
- return mStatus_NoError;
}
mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor
- // Reverse what was done in udsSupportAddFDToEventLoop().
{
- CFSocketEventSource *iSource;
-
- for (iSource=(CFSocketEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ KQSocketEventSource **p = &gEventSources;
+ while (*p && (*p)->fd != fd) p = &(*p)->next;
+ if (*p)
{
- if (fd == iSource->fd)
- {
- RemoveFromList(&gEventSources, iSource);
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource->RLS, kCFRunLoopDefaultMode);
- CFRunLoopSourceInvalidate(iSource->RLS);
- CFRelease(iSource->RLS);
- CFSocketInvalidate(iSource->cfs); // Note: Also closes the underlying socket
- CFRelease(iSource->cfs);
- free(iSource);
- return mStatus_NoError;
- }
+ KQSocketEventSource *s = *p;
+ *p = (*p)->next;
+ // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
+ // causes the kernel to automatically remove any associated kevents
+ close(s->fd);
+ freeL("KQSocketEventSource", s);
+ return mStatus_NoError;
}
return mStatus_NoSuchNameErr;
}
asm(".desc ___crashreporter_info__, 0x10");
// For convenience when using the "strings" command, this is the last thing in the file
-mDNSexport const char mDNSResponderVersionString[] = STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+// The "@(#) " pattern is a special prefix the "what" command looks for
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: helper-error.h,v $
+Revision 1.7 2007/09/12 00:42:47 mcguire
+<rdar://problem/5468236> BTMM: Need to clean up security associations
+
+Revision 1.6 2007/09/04 22:32:58 mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.5 2007/08/29 21:42:12 mcguire
+<rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
+
+Revision 1.4 2007/08/23 21:15:49 cheshire
+Added $Log header
+
+Revision 1.3 2007/08/23 21:04:44 cheshire
+Tidied up alignment of error message list
+
+Revision 1.2 2007/08/18 01:02:03 mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.1 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+
+ */
+
+ERROR(kmDNSHelperCommunicationFailed, "Mach communication failed")
+ERROR(kmDNSHelperNotAuthorized, "Not authorized")
+ERROR(kmDNSHelperCreationFailed, "Object creation failed")
+ERROR(kmDNSHelperInvalidPList, "Invalid property list")
+ERROR(kmDNSHelperDynamicStoreFailed, "Could not create dynamic store session")
+ERROR(kmDNSHelperDynamicStoreSetFailed, "Could not set dynamic store configuration")
+ERROR(kmDNSHelperInvalidNameKey, "Invalid name key")
+ERROR(kmDNSHelperInvalidConfigKey, "Invalid configuration key")
+ERROR(kmDNSHelperTypeError, "Object was not of expected type")
+ERROR(kmDNSHelperPreferencesFailed, "Could not create preferences session")
+ERROR(kmDNSHelperPreferencesLockFailed, "Could not lock preferences")
+ERROR(kmDNSHelperPreferencesSetFailed, "Could not update preferences")
+ERROR(kmDNSHelperKeychainCopyDefaultFailed, "Could not copy keychain default")
+ERROR(kmDNSHelperKeychainSearchCreationFailed, "Could not create keychain search")
+ERROR(kmDNSHelperPListWriteFailed, "Could not write property list to stream")
+ERROR(kmDNSHelperResultTooLarge, "Result too large")
+ERROR(kmDNSHelperInterfaceCreationFailed, "Could not create auto-tunnel interface")
+ERROR(kmDNSHelperInterfaceDeletionFailed, "Could not delete auto-tunnel interface")
+ERROR(kmDNSHelperInvalidInterfaceState, "Invalid interface state requested")
+ERROR(kmDNSHelperInvalidServerState, "Invalid server state requested")
+ERROR(kmDNSHelperRacoonConfigCreationFailed, "Could not create racoon configuration file")
+ERROR(kmDNSHelperRacoonStartFailed, "Could not start racoon")
+ERROR(kmDNSHelperRacoonNotificationFailed, "Could not notify racoon")
+ERROR(kmDNSHelperInvalidTunnelSetKeysOperation, "Invalid tunnel setkey operation requested")
+ERROR(kmDNSHelperInvalidNetworkAddress, "Invalid network address")
+ERROR(kmDNSHelperRouteAdditionFailed, "Could not add route")
+ERROR(kmDNSHelperRouteDeletionFailed, "Could not remove route")
+ERROR(kmDNSHelperRoutingSocketCreationFailed, "Could not create routing socket")
+ERROR(kmDNSHelperDatagramSocketCreationFailed, "Could not create datagram socket")
+ERROR(kmDNSHelperIPsecPolicyCreationFailed, "Could not create IPsec policy")
+ERROR(kmDNSHelperIPsecPolicySetFailed, "Could not set IPsec policy")
+ERROR(kmDNSHelperIPsecRemoveSAFailed, "Could not remove IPsec SA")
+ERROR(kmDNSHelperIPsecPolicySocketCreationFailed, "Could not create IPsec policy socket")
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: helper-main.c,v $
+Revision 1.13 2007/09/21 16:13:14 cheshire
+Additional Tiger compatibility fix: After bootstrap_check_in, we need to give
+ourselves a Mach "send" right to the port, otherwise our ten-second idle timeout
+mechanism is not able to send the "mDNSIdleExit" message to itself
+
+Revision 1.12 2007/09/20 22:26:20 cheshire
+Add necessary bootstrap_check_in() in Tiger compatibility code (not used on Leopard)
+
+Revision 1.11 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.10 2007/09/09 02:21:17 mcguire
+<rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
+
+Revision 1.9 2007/09/07 22:44:03 mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.8 2007/09/07 22:24:36 vazquez
+<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
+
+Revision 1.7 2007/08/31 18:09:32 cheshire
+<rdar://problem/5434050> Restore ability to run mDNSResponder on Tiger
+
+Revision 1.6 2007/08/31 17:45:13 cheshire
+Allow maxidle time of zero, meaning "run indefinitely"
+
+Revision 1.5 2007/08/31 00:09:54 cheshire
+Deleted extraneous whitespace (shortened code from 260 lines to 160)
+
+Revision 1.4 2007/08/28 00:33:04 jgraessley
+<rdar://problem/5423932> Selective compilation options
+
+Revision 1.3 2007/08/23 23:21:24 cheshire
+Tiger compatibility: Use old bootstrap_register() instead of Leopard-only bootstrap_register2()
+
+Revision 1.2 2007/08/23 21:36:17 cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.1 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#define _FORTIFY_SOURCE 2
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/cdefs.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <servers/bootstrap.h>
+#include <asl.h>
+#include <launch.h>
+#include <pwd.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <Security/Security.h>
+#include "helper.h"
+#include "helper-server.h"
+#include "helpermsg.h"
+#include "helpermsgServer.h"
+
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#endif
+
+#ifndef LAUNCH_JOBKEY_MACHSERVICES
+#define LAUNCH_JOBKEY_MACHSERVICES "MachServices"
+#define LAUNCH_DATA_MACHPORT 10
+#define launch_data_get_machport launch_data_get_fd
+#endif
+
+union max_msg_size
+ {
+ union __RequestUnion__proxy_helper_subsystem req;
+ union __ReplyUnion__proxy_helper_subsystem rep;
+ };
+
+static const mach_msg_size_t MAX_MSG_SIZE = sizeof(union max_msg_size) + MAX_TRAILER_SIZE;
+static aslclient logclient = NULL;
+static int opt_debug;
+static pthread_t idletimer_thread;
+
+unsigned long maxidle = 10;
+unsigned long actualidle = 3600;
+
+CFRunLoopRef gRunLoop = NULL;
+CFRunLoopTimerRef gTimer = NULL;
+
+static void helplogv(int level, const char *fmt, va_list ap)
+ {
+ if (NULL == logclient) { vfprintf(stderr, fmt, ap); fflush(stderr); }
+ else asl_vlog(logclient, NULL, level, fmt, ap);
+ }
+
+void helplog(int level, const char *fmt, ...)
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ helplogv(level, fmt, ap);
+ va_end(ap);
+ }
+
+static void initialize_logging(void)
+ {
+ logclient = asl_open(NULL, kmDNSHelperServiceName, (opt_debug ? ASL_OPT_STDERR : 0));
+ if (NULL == logclient) { fprintf(stderr, "Could not initialize ASL logging.\n"); fflush(stderr); return; }
+ if (opt_debug) asl_set_filter(logclient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+ }
+
+static void initialize_id(void)
+ {
+ static char login[] = "_mdnsresponder";
+ struct passwd *pwd = getpwnam(login);
+
+ if (!pwd) { helplog(ASL_LEVEL_ERR, "Could not find account name `%s'. I will only help root.", login); return; }
+ mDNSResponderUID = pwd->pw_uid;
+ mDNSResponderGID = pwd->pw_gid;
+ }
+
+static void diediedie(CFRunLoopTimerRef timer, void *context)
+ {
+ debug("entry");
+ assert(gTimer == timer);
+ if (maxidle)
+ (void)proxy_mDNSIdleExit((mach_port_t)context);
+ }
+
+void pause_idle_timer(void)
+ {
+ debug("entry");
+ assert(gTimer);
+ assert(gRunLoop);
+ CFRunLoopRemoveTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode);
+ }
+
+void unpause_idle_timer(void)
+ {
+ debug("entry");
+ assert(gRunLoop);
+ assert(gTimer);
+ CFRunLoopAddTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode);
+ }
+
+void update_idle_timer(void)
+ {
+ debug("entry");
+ assert(gTimer);
+ CFRunLoopTimerSetNextFireDate(gTimer, CFAbsoluteTimeGetCurrent() + actualidle);
+ }
+
+static void *idletimer(void *context)
+ {
+ debug("entry context=%p", context);
+ gRunLoop = CFRunLoopGetCurrent();
+
+ unpause_idle_timer();
+
+ for (;;)
+ {
+ debug("Running CFRunLoop");
+ CFRunLoopRun();
+ sleep(1);
+ }
+
+ return NULL;
+ }
+
+static void initialize_timer(mach_port_t port)
+ {
+ CFRunLoopTimerContext cxt = {0, (void *)port, NULL, NULL, NULL};
+ gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, &cxt);
+ int err = 0;
+
+ debug("entry port=%p", port);
+ if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, (void *)port)))
+ helplog(ASL_LEVEL_ERR, "Could not start idletimer thread: %s", strerror(err));
+ }
+
+static mach_port_t checkin(char *service_name)
+ {
+ kern_return_t kr = KERN_SUCCESS;
+ mach_port_t port = MACH_PORT_NULL;
+ launch_data_t msg = NULL, reply = NULL, datum = NULL;
+
+ if (NULL == (msg = launch_data_new_string(LAUNCH_KEY_CHECKIN)))
+ { helplog(ASL_LEVEL_ERR, "Could not create checkin message for launchd."); goto fin; }
+ if (NULL == (reply = launch_msg(msg)))
+ { helplog(ASL_LEVEL_ERR, "Could not message launchd."); goto fin; }
+ if (LAUNCH_DATA_ERRNO == launch_data_get_type(reply))
+ {
+ if (launch_data_get_errno(reply) == EACCES) { launch_data_free(msg); launch_data_free(reply); return(MACH_PORT_NULL); }
+ helplog(ASL_LEVEL_ERR, "Launchd checkin failed: %s.", strerror(launch_data_get_errno(reply))); goto fin;
+ }
+ if (NULL == (datum = launch_data_dict_lookup(reply, LAUNCH_JOBKEY_MACHSERVICES)) || LAUNCH_DATA_DICTIONARY != launch_data_get_type(datum))
+ { helplog(ASL_LEVEL_ERR, "Launchd reply does not contain %s dictionary.", LAUNCH_JOBKEY_MACHSERVICES); goto fin; }
+ if (NULL == (datum = launch_data_dict_lookup(datum, service_name)) || LAUNCH_DATA_MACHPORT != launch_data_get_type(datum))
+ { helplog(ASL_LEVEL_ERR, "Launchd reply does not contain %s Mach port.", service_name); goto fin; }
+ if (MACH_PORT_NULL == (port = launch_data_get_machport(datum)))
+ { helplog(ASL_LEVEL_ERR, "Launchd gave me a null Mach port."); goto fin; }
+ if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
+ { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto fin; }
+
+fin:
+ if (NULL != msg) launch_data_free(msg);
+ if (NULL != reply) launch_data_free(reply);
+ if (MACH_PORT_NULL == port) exit(EXIT_FAILURE);
+ return port;
+ }
+
+static mach_port_t register_service(const char *service_name)
+ {
+ mach_port_t port = MACH_PORT_NULL;
+ kern_return_t kr;
+
+ if (KERN_SUCCESS == (kr = bootstrap_check_in(bootstrap_port, (char *)service_name, &port)))
+ {
+ if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
+ helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr));
+ else
+ return port;
+ }
+ if (KERN_SUCCESS != (kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)))
+ { helplog(ASL_LEVEL_ERR, "mach_port_allocate: %s", mach_error_string(kr)); goto error; }
+ if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
+ { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto error; }
+ // XXX bootstrap_register does not modify its second argument, but the prototype does not include const.
+ if (KERN_SUCCESS != (kr = bootstrap_register(bootstrap_port, (char *)service_name, port)))
+ { helplog(ASL_LEVEL_ERR, "bootstrap_register failed: %s", mach_error_string(kr)); goto error; }
+ return port;
+error:
+ if (MACH_PORT_NULL != port) mach_port_deallocate(mach_task_self(), port);
+ return MACH_PORT_NULL;
+ }
+
+int main(int ac, char *av[])
+ {
+ char *p = NULL;
+ kern_return_t kr = KERN_FAILURE;
+ mach_port_t port = MACH_PORT_NULL;
+ long n;
+ int ch;
+
+ while ((ch = getopt(ac, av, "dt:")) != -1)
+ switch (ch)
+ {
+ case 'd': opt_debug = 1; break;
+ case 't':
+ n = strtol(optarg, &p, 0);
+ if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0)
+ { fprintf(stderr, "Invalid idle timeout: %s\n", optarg); exit(EXIT_FAILURE); }
+ maxidle = n;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n");
+ exit(EXIT_FAILURE);
+ }
+ ac -= optind;
+ av += optind;
+
+ initialize_logging();
+ helplog(ASL_LEVEL_INFO, "Starting");
+ initialize_id();
+
+#ifndef NO_SECURITYFRAMEWORK
+ // We should normally be running as a system daemon. However, that might not be the case in some scenarios (e.g. debugging).
+ // Explicitly ensure that our Keychain operations utilize the system domain.
+ SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+#endif
+ if (!opt_debug)
+ {
+ port = checkin(kmDNSHelperServiceName);
+ if (!port) helplog(ASL_LEVEL_ERR, "Launchd provided no launchdata; will open Mach port explicitly");
+ }
+ if (!port) port = register_service(kmDNSHelperServiceName);
+
+ if (maxidle) actualidle = maxidle;
+ initialize_timer(port);
+
+ kr = mach_msg_server(helper_server, MAX_MSG_SIZE, port,
+ MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
+ if (KERN_SUCCESS != kr)
+ { helplog(ASL_LEVEL_ERR, "mach_msg_server: %s\n", mach_error_string(kr)); exit(EXIT_FAILURE); }
+ exit(EXIT_SUCCESS);
+ }
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// For convenience when using the "strings" command, this is the last thing in the file
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) mDNSResponderHelper " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: helper-server.h,v $
+Revision 1.3 2007/09/07 22:44:03 mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.2 2007/08/23 21:39:01 cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.1 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#ifndef H_HELPER_SERVER_H
+#define H_HELPER_SERVER_H
+
+extern void helplog(int, const char *, ...);
+extern void pause_idle_timer(void);
+extern void unpause_idle_timer(void);
+extern void update_idle_timer(void);
+extern uid_t mDNSResponderUID;
+extern uid_t mDNSResponderGID;
+extern CFRunLoopRef gRunLoop;
+#define debug(...) debug_(__func__, __VA_ARGS__)
+extern void debug_(const char *func, const char *fmt, ...);
+
+#endif /* H_HELPER_SERVER_H */
--- /dev/null
+/*
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: helper-stubs.c,v $
+Revision 1.5 2007/09/07 22:44:03 mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.4 2007/09/04 22:32:58 mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.3 2007/08/23 21:44:55 cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.2 2007/08/18 01:02:03 mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.1 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/vm_map.h>
+#include <servers/bootstrap.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include "mDNSDebug.h"
+#include "helper.h"
+#include "helpermsg.h"
+
+#define ERROR(x, y) y,
+static const char *errorstring[] =
+ {
+ #include "helper-error.h"
+ NULL
+ };
+#undef ERROR
+
+static mach_port_t
+getHelperPort(int retry)
+ {
+ static mach_port_t port = MACH_PORT_NULL;
+
+ if (retry)
+ port = MACH_PORT_NULL;
+ if (port == MACH_PORT_NULL &&
+ BOOTSTRAP_SUCCESS != bootstrap_look_up(bootstrap_port,
+ kmDNSHelperServiceName, &port))
+ LogMsg("%s: cannot contact helper", __func__);
+ return port;
+ }
+
+const char *
+mDNSHelperError(int err)
+ {
+ const char *p = "<unknown error>";
+ if (mDNSHelperErrorBase < err && mDNSHelperErrorEnd > err)
+ p = errorstring[err - mDNSHelperErrorBase - 1];
+ return p;
+ }
+
+
+/* Ugly but handy. */
+#define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) for (;;) {
+
+#define MACHRETRYLOOP_END(kr, retry, err, fin) \
+ if (KERN_SUCCESS == (kr)) break; \
+ else if (MACH_SEND_INVALID_DEST == (kr) && 0 == (retry)++) continue; \
+ else \
+ { \
+ (err) = kmDNSHelperCommunicationFailed; \
+ LogMsg("%s: Mach communication failed: %s", __func__, mach_error_string(kr)); \
+ goto fin; \
+ } \
+ } \
+ if (0 != (err)) { LogMsg("%s: %s", __func__, mDNSHelperError((err))); goto fin; }
+
+int
+mDNSPreferencesSetName(int key, domainlabel* old, domainlabel* new)
+ {
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0;
+ int err = 0;
+ char oldname[MAX_DOMAIN_LABEL+1] = {0};
+ char newname[MAX_DOMAIN_LABEL+1] = {0};
+ ConvertDomainLabelToCString_unescaped(old, oldname);
+ if (new) ConvertDomainLabelToCString_unescaped(new, newname);
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, oldname, newname, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+ return err;
+ }
+
+int
+mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value)
+ {
+ CFWriteStreamRef stream = NULL;
+ CFDataRef bytes = NULL;
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0;
+ int err = 0;
+
+ if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL,
+ NULL)))
+ {
+ err = kmDNSHelperCreationFailed;
+ LogMsg("%s: CFWriteStreamCreateWithAllocatedBuffers failed",
+ __func__);
+ goto fin;
+ }
+ CFWriteStreamOpen(stream);
+ if (0 == CFPropertyListWriteToStream(value, stream,
+ kCFPropertyListBinaryFormat_v1_0, NULL))
+ {
+ err = kmDNSHelperPListWriteFailed;
+ LogMsg("%s: CFPropertyListWriteToStream failed", __func__);
+ goto fin;
+ }
+ if (NULL == (bytes = CFWriteStreamCopyProperty(stream,
+ kCFStreamPropertyDataWritten)))
+ {
+ err = kmDNSHelperCreationFailed;
+ LogMsg("%s: CFWriteStreamCopyProperty failed", __func__);
+ goto fin;
+ }
+ CFWriteStreamClose(stream);
+ CFRelease(stream);
+ stream = NULL;
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSDynamicStoreSetConfig(getHelperPort(retry), key,
+ (vm_offset_t)CFDataGetBytePtr(bytes),
+ CFDataGetLength(bytes), &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+ if (NULL != stream)
+ {
+ CFWriteStreamClose(stream);
+ CFRelease(stream);
+ }
+ if (NULL != bytes)
+ CFRelease(bytes);
+ return err;
+ }
+
+int
+mDNSKeychainGetSecrets(CFArrayRef *result)
+ {
+ CFPropertyListRef plist = NULL;
+ CFDataRef bytes = NULL;
+ kern_return_t kr = KERN_FAILURE;
+ unsigned int numsecrets = 0;
+ void *secrets = NULL;
+ mach_msg_type_number_t secretsCnt = 0;
+ int retry = 0;
+ int err = 0;
+
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry),
+ &numsecrets, (vm_offset_t *)&secrets, &secretsCnt, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+ if (0 == numsecrets)
+ goto fin;
+ if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
+ secrets, secretsCnt, kCFAllocatorNull)))
+ {
+ err = kmDNSHelperCreationFailed;
+ LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__);
+ goto fin;
+ }
+ if (NULL == (plist = CFPropertyListCreateFromXMLData(
+ kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL)))
+ {
+ err = kmDNSHelperInvalidPList;
+ LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__);
+ goto fin;
+ }
+ if (CFArrayGetTypeID() != CFGetTypeID(plist))
+ {
+ err = kmDNSHelperTypeError;
+ LogMsg("%s: Unexpected result type", __func__);
+ CFRelease(plist);
+ plist = NULL;
+ goto fin;
+ }
+ *result = (CFArrayRef)plist;
+
+fin:
+ if (NULL != bytes)
+ CFRelease(bytes);
+ if (NULL != secrets)
+ vm_deallocate(mach_task_self(), (vm_offset_t)secrets,
+ secretsCnt);
+ return err;
+ }
+
+int
+mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t address)
+ {
+ kern_return_t kr = KERN_SUCCESS;
+ int retry = 0;
+ int err = 0;
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSAutoTunnelInterfaceUpDown(getHelperPort(retry),
+ updown, address, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+ return err;
+ }
+
+int
+mDNSConfigureServer(int updown, const char *keydata)
+ {
+ kern_return_t kr = KERN_SUCCESS;
+ int retry = 0;
+ int err = 0;
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, keydata, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+ return err;
+ }
+
+int
+mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
+ v4addr_t local_outer, short local_port, v6addr_t remote_inner,
+ v4addr_t remote_outer, short remote_port, const char *keydata)
+ {
+ kern_return_t kr = KERN_SUCCESS;
+ const char *p = NULL;
+ int retry = 0;
+ int err = 0;
+
+ if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
+ p = keydata;
+ else
+ p = "";
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSAutoTunnelSetKeys(getHelperPort(retry), replacedelete,
+ local_inner, local_outer, local_port, remote_inner, remote_outer,
+ remote_port, keydata, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+ return err;
+ }
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: helper.c,v $
+Revision 1.20 2007/09/12 18:07:44 cheshire
+Fix compile errors ("passing argument from incompatible pointer type")
+
+Revision 1.19 2007/09/12 00:42:47 mcguire
+<rdar://problem/5468236> BTMM: Need to clean up security associations
+
+Revision 1.18 2007/09/12 00:40:16 mcguire
+<rdar://problem/5469660> 9A547: Computer Name had incorrectly encoded unicode
+
+Revision 1.17 2007/09/09 02:21:17 mcguire
+<rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
+
+Revision 1.16 2007/09/07 22:44:03 mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.15 2007/09/07 22:24:36 vazquez
+<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
+
+Revision 1.14 2007/09/06 20:39:05 cheshire
+Added comment explaining why we allow both "ddns" and "sndd" as valid item types
+The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
+
+Revision 1.13 2007/09/04 22:32:58 mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.12 2007/08/29 21:42:12 mcguire
+<rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
+
+Revision 1.11 2007/08/28 00:33:04 jgraessley
+<rdar://problem/5423932> Selective compilation options
+
+Revision 1.10 2007/08/27 22:16:38 mcguire
+<rdar://problem/5437362> BTMM: MTU should be set to 1280
+
+Revision 1.9 2007/08/27 22:13:59 mcguire
+<rdar://problem/5437373> BTMM: IPSec security associations should have a shorter timeout
+
+Revision 1.8 2007/08/23 21:49:51 cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.7 2007/08/23 00:29:05 mcguire
+<rdar://problem/5425800> BTMM: IPSec policy not installed in some situations - connections fail
+
+Revision 1.6 2007/08/18 01:02:03 mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.5 2007/08/18 00:59:55 mcguire
+<rdar://problem/5392568> Blocked: BTMM: Start racoon with '-e' parameter
+
+Revision 1.4 2007/08/16 01:00:06 mcguire
+<rdar://problem/5392548> BTMM: Install generate IPsec policies to block non-BTMM traffic
+
+Revision 1.3 2007/08/15 23:20:28 mcguire
+<rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
+
+Revision 1.2 2007/08/10 22:30:39 mcguire
+<rdar://problem/5400259> BTMM: racoon config files are not always the correct mode
+
+Revision 1.1 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#include <sys/cdefs.h>
+#include <arpa/inet.h>
+#include <bsm/libbsm.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#include <netinet6/ipsec.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <asl.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <Security/Security.h>
+#include <SystemConfiguration/SCDynamicStore.h>
+#include <SystemConfiguration/SCPreferencesSetSpecific.h>
+#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
+#include "mDNSEmbeddedAPI.h"
+#include "dns_sd.h"
+#include "dnssd_ipc.h"
+#include "libpfkey.h"
+#include "helper.h"
+#include "helpermsgServer.h"
+#include "helper-server.h"
+
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#endif
+
+typedef struct sadb_x_policy *ipsec_policy_t;
+
+uid_t mDNSResponderUID;
+gid_t mDNSResponderGID;
+static const char kTunnelAddressInterface[] = "lo0";
+
+void
+debug_(const char *func, const char *fmt, ...)
+ {
+ char buf[2048];
+ va_list ap;
+ ssize_t n = snprintf(buf, sizeof(buf), "%s: ", func);
+
+ if (n >= (int)sizeof(buf))
+ return;
+ va_start(ap, fmt);
+ vsnprintf(&buf[n], sizeof(buf)-n, fmt, ap);
+ va_end(ap);
+ helplog(ASL_LEVEL_DEBUG, buf);
+ }
+
+static int
+authorized(audit_token_t *token)
+ {
+ int ok = 0;
+ pid_t pid = (pid_t)-1;
+ uid_t euid = (uid_t)-1;
+
+ audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL,
+ NULL);
+ ok = (euid == mDNSResponderUID || euid == 0);
+ if (!ok)
+ helplog(ASL_LEVEL_NOTICE,
+ "Unauthorized access by euid=%lu pid=%lu",
+ (unsigned long)euid, (unsigned long)pid);
+ return ok;
+ }
+
+static void
+closefds(int from)
+ {
+ int fd = 0;
+ struct dirent entry, *entryp = NULL;
+ DIR *dirp = opendir("/dev/fd");
+
+ if (dirp == NULL)
+ {
+ /* fall back to the erroneous getdtablesize method */
+ for (fd = from; fd < getdtablesize(); ++fd)
+ close(fd);
+ return;
+ }
+ while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
+ {
+ fd = atoi(entryp->d_name);
+ if (fd >= from && fd != dirfd(dirp))
+ close(fd);
+ }
+ closedir(dirp);
+ }
+
+kern_return_t
+do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token)
+ {
+ debug("entry");
+ if (!authorized(&token))
+ goto fin;
+ helplog(ASL_LEVEL_INFO, "Idle exit");
+ exit(0);
+
+fin:
+ debug("fin");
+ return KERN_SUCCESS;
+ }
+
+kern_return_t
+do_mDNSDynamicStoreSetConfig(__unused mach_port_t port, int key,
+ vm_offset_t value, mach_msg_type_number_t valueCnt, int *err,
+ audit_token_t token)
+ {
+ CFStringRef sckey = NULL;
+ CFDataRef bytes = NULL;
+ CFPropertyListRef plist = NULL;
+ SCDynamicStoreRef store = NULL;
+
+ debug("entry");
+ *err = 0;
+ if (!authorized(&token))
+ {
+ *err = kmDNSHelperNotAuthorized;
+ goto fin;
+ }
+ switch ((enum mDNSDynamicStoreSetConfigKey)key)
+ {
+ case kmDNSMulticastConfig:
+ sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
+ break;
+ case kmDNSDynamicConfig:
+ sckey = CFSTR("State:/Network/DynamicDNS");
+ break;
+ case kmDNSPrivateConfig:
+ sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
+ break;
+ case kmDNSBackToMyMacConfig:
+ sckey = CFSTR("State:/Network/BackToMyMac");
+ break;
+ default:
+ debug("unrecognized key %d", key);
+ *err = kmDNSHelperInvalidConfigKey;
+ goto fin;
+ }
+ if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
+ valueCnt, kCFAllocatorNull)))
+ {
+ debug("CFDataCreateWithBytesNoCopy of value failed");
+ *err = kmDNSHelperCreationFailed;
+ goto fin;
+ }
+ if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
+ kCFPropertyListImmutable, NULL)))
+ {
+ debug("CFPropertyListCreateFromXMLData of bytes failed");
+ *err = kmDNSHelperInvalidPList;
+ goto fin;
+ }
+ CFRelease(bytes);
+ bytes = NULL;
+ if (NULL == (store = SCDynamicStoreCreate(NULL,
+ CFSTR(kmDNSHelperServiceName), NULL, NULL)))
+ {
+ debug("SCDynamicStoreCreate failed");
+ *err = kmDNSHelperDynamicStoreFailed;
+ goto fin;
+ }
+ SCDynamicStoreSetValue(store, sckey, plist);
+ *err = 0;
+ debug("succeeded");
+
+fin:
+ if (0 != *err)
+ debug("failed err=%d", *err);
+ if (NULL != bytes)
+ CFRelease(bytes);
+ if (NULL != plist)
+ CFRelease(plist);
+ if (NULL != store)
+ CFRelease(store);
+ vm_deallocate(mach_task_self(), value, valueCnt);
+ update_idle_timer();
+ return KERN_SUCCESS;
+ }
+
+char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
+char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
+char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
+char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
+
+static CFStringRef CFS_OQ = NULL;
+static CFStringRef CFS_CQ = NULL;
+static CFStringRef CFS_Format = NULL;
+static CFStringRef CFS_ComputerName = NULL;
+static CFStringRef CFS_ComputerNameMsg = NULL;
+static CFStringRef CFS_LocalHostName = NULL;
+static CFStringRef CFS_LocalHostNameMsg = NULL;
+static CFStringRef CFS_Problem = NULL;
+
+static CFUserNotificationRef gNotification = NULL;
+static CFRunLoopSourceRef gNotificationRLS = NULL;
+
+static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
+ {
+ debug("entry");
+ (void)responseFlags; // Unused
+ if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
+ if (gNotificationRLS)
+ {
+ // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
+ // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
+ CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
+ CFRelease(gNotificationRLS);
+ gNotificationRLS = NULL;
+ CFRelease(gNotification);
+ gNotification = NULL;
+ }
+ // By dismissing the alert, the user has conceptually acknowleged the rename.
+ // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
+ // If we get *another* conflict, the new alert should refer to the 'old' name
+ // as now being "computer-2.local", not "computer.local"
+ usercompname[0] = 0;
+ userhostname[0] = 0;
+ lastcompname[0] = 0;
+ lasthostname[0] = 0;
+ update_idle_timer();
+ unpause_idle_timer();
+ }
+
+static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
+ {
+ CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!dictionary) return;
+
+ debug("entry");
+
+ CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
+ CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
+
+ CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
+ if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
+
+ if (gNotification) // If notification already on-screen, update it in place
+ CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
+ else // else, we need to create it
+ {
+ SInt32 error;
+ gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
+ if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; }
+ gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
+ if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
+ // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
+ // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
+ CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
+ debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS);
+ pause_idle_timer();
+ }
+
+ CFRelease(dictionary);
+ }
+
+static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
+ {
+ CFMutableArrayRef alertHeader = NULL;
+
+ const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
+ // NULL newname means we've given up trying to construct a name that doesn't conflict
+ const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8) : NULL;
+ // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
+ // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
+ // can never be one that occurs in the Localizable.strings translation file.
+ if (!cfoldname)
+ helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname);
+ else if (newname && !cfnewname)
+ helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname);
+ else
+ {
+ const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
+ const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
+
+ alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ if (!s1)
+ helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname);
+ else if (cfnewname && !s2)
+ helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname);
+ else if (!alertHeader)
+ helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification");
+ else
+ {
+ // Make sure someone is logged in. We don't want this popping up over the login window
+ uid_t uid;
+ gid_t gid;
+ CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
+ if (userName)
+ {
+ CFRelease(userName);
+ CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller
+ CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ);
+ CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. "));
+ if (s2)
+ {
+ CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to "));
+ CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ);
+ CFArrayAppendValue(alertHeader, CFSTR("."));
+ }
+ else
+ CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
+ }
+ }
+ if (s1) CFRelease(s1);
+ if (s2) CFRelease(s2);
+ }
+ if (cfoldname) CFRelease(cfoldname);
+ if (cfnewname) CFRelease(cfnewname);
+
+ return alertHeader;
+ }
+
+static void update_notification(void)
+ {
+ debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
+ if (!CFS_OQ)
+ {
+ // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
+ // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
+ // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
+ CFS_OQ = CFStringCreateWithCString(NULL, "“", kCFStringEncodingUTF8);
+ CFS_CQ = CFStringCreateWithCString(NULL, "”", kCFStringEncodingUTF8);
+ CFS_Format = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8);
+ CFS_ComputerName = CFStringCreateWithCString(NULL, "The name of your computer ", kCFStringEncodingUTF8);
+ CFS_ComputerNameMsg = CFStringCreateWithCString(NULL, "To change the name of your computer, "
+ "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8);
+ CFS_LocalHostName = CFStringCreateWithCString(NULL, "This computer’s local hostname ", kCFStringEncodingUTF8);
+ CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, "
+ "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8);
+ CFS_Problem = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. "
+ "Please inform your network administrator.", kCFStringEncodingUTF8);
+ }
+
+ if (!usercompname[0] && !userhostname[0])
+ {
+ if (gNotificationRLS)
+ {
+ debug("canceling notification %p", gNotification);
+ CFUserNotificationCancel(gNotification);
+ unpause_idle_timer();
+ }
+ }
+ else
+ {
+ CFMutableArrayRef header = NULL;
+ CFStringRef* subtext = NULL;
+ if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict
+ {
+ header = GetHeader(userhostname, NULL, CFS_LocalHostName, ".local");
+ subtext = &CFS_Problem;
+ }
+ else if (usercompname[0])
+ {
+ header = GetHeader(usercompname, lastcompname, CFS_ComputerName, "");
+ subtext = &CFS_ComputerNameMsg;
+ }
+ else
+ {
+ header = GetHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
+ subtext = &CFS_LocalHostNameMsg;
+ }
+ ShowNameConflictNotification(header, *subtext);
+ CFRelease(header);
+ }
+ }
+
+kern_return_t
+do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, int *err, audit_token_t token)
+ {
+ SCPreferencesRef session = NULL;
+ Boolean ok = FALSE;
+ Boolean locked = FALSE;
+ CFStringRef cfstr = NULL;
+ char* user = NULL;
+ char* last = NULL;
+ Boolean needUpdate = FALSE;
+
+ debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
+ *err = 0;
+ if (!authorized(&token))
+ {
+ *err = kmDNSHelperNotAuthorized;
+ goto fin;
+ }
+ switch ((enum mDNSPreferencesSetNameKey)key)
+ {
+ case kmDNSComputerName:
+ user = usercompname;
+ last = lastcompname;
+ break;
+ case kmDNSLocalHostName:
+ user = userhostname;
+ last = lasthostname;
+ break;
+ default:
+ debug("unrecognized key: %d", key);
+ *err = kmDNSHelperInvalidNameKey;
+ goto fin;
+ }
+
+ if (!last)
+ {
+ helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__);
+ goto fin;
+ }
+
+ if (!user)
+ {
+ helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__);
+ goto fin;
+ }
+
+ if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
+ {
+ // if we've changed the name, but now someone else has set it to something different, we no longer need the notification
+ if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
+ {
+ last[0] = 0;
+ user[0] = 0;
+ needUpdate = TRUE;
+ }
+ goto fin;
+ }
+ else
+ {
+ if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
+ {
+ strncpy(last, new, MAX_DOMAIN_LABEL);
+ needUpdate = TRUE;
+ }
+ }
+
+ if (!user[0])
+ {
+ strncpy(user, old, MAX_DOMAIN_LABEL);
+ needUpdate = TRUE;
+ }
+
+ if (!new[0]) // we've given up trying to construct a name that doesn't conflict
+ goto fin;
+
+ cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
+
+ session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL);
+
+ if (cfstr == NULL || session == NULL)
+ {
+ debug("SCPreferencesCreate failed");
+ *err = kmDNSHelperPreferencesFailed;
+ goto fin;
+ }
+ if (!SCPreferencesLock(session, 0))
+ {
+ debug("lock failed");
+ *err = kmDNSHelperPreferencesLockFailed;
+ goto fin;
+ }
+ locked = TRUE;
+
+ switch ((enum mDNSPreferencesSetNameKey)key)
+ {
+ case kmDNSComputerName:
+ {
+ // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
+ // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
+ // Note that this encoding is not used for the computer name, but since both are set by the same call,
+ // we need to take care to set the name without changing the character set.
+ CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding);
+ if (unused) { CFRelease(unused); unused = NULL; }
+ else encoding = kCFStringEncodingUTF8;
+
+ ok = SCPreferencesSetComputerName(session, cfstr, encoding);
+ }
+ break;
+ case kmDNSLocalHostName:
+ ok = SCPreferencesSetLocalHostName(session, cfstr);
+ break;
+ default:
+ break;
+ }
+
+ if (!ok || !SCPreferencesCommitChanges(session) ||
+ !SCPreferencesApplyChanges(session))
+ {
+ debug("SCPreferences update failed");
+ *err = kmDNSHelperPreferencesSetFailed;
+ goto fin;
+ }
+ *err = 0;
+ debug("succeeded");
+
+fin:
+ if (0 != *err)
+ debug("failed err=%d", *err);
+ if (NULL != cfstr)
+ CFRelease(cfstr);
+ if (NULL != session)
+ {
+ if (locked)
+ SCPreferencesUnlock(session);
+ CFRelease(session);
+ }
+ update_idle_timer();
+ if (needUpdate) update_notification();
+ return KERN_SUCCESS;
+ }
+
+enum DNSKeyFormat
+ {
+ formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem
+ };
+
+// On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
+// I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
+// therefore I need to add some byte swapping in this API to make this four-character string backwards too."
+// To cope with this we allow *both* "ddns" and "sndd" as valid item types.
+
+static const char dnsprefix[] = "dns:";
+static const char ddns[] = "ddns";
+static const char ddnsrev[] = "sndd";
+
+#ifndef NO_SECURITYFRAMEWORK
+static enum DNSKeyFormat
+getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
+ {
+ static UInt32 tags[3] =
+ {
+ kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr
+ };
+ static SecKeychainAttributeInfo attributeInfo =
+ {
+ sizeof(tags)/sizeof(tags[0]), tags, NULL
+ };
+ SecKeychainAttributeList *attributes = NULL;
+ enum DNSKeyFormat format;
+ Boolean malformed = FALSE;
+ OSStatus status = noErr;
+ int i = 0;
+
+ *attributesp = NULL;
+ if (noErr != (status = SecKeychainItemCopyAttributesAndData(item,
+ &attributeInfo, NULL, &attributes, NULL, NULL)))
+ {
+ debug("SecKeychainItemCopyAttributesAndData %d - skipping",
+ status);
+ goto skip;
+ }
+ if (attributeInfo.count != attributes->count)
+ malformed = TRUE;
+ for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
+ if (attributeInfo.tag[i] != attributes->attr[i].tag)
+ malformed = TRUE;
+ if (malformed)
+ {
+ debug(
+ "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
+ goto skip;
+ }
+ debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
+ (int)attributes->attr[0].length, attributes->attr[0].data,
+ (int)attributes->attr[1].length, attributes->attr[1].data,
+ (int)attributes->attr[2].length, attributes->attr[2].data);
+ if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
+ sizeof(dnsprefix)-1)
+ {
+ debug("kSecServiceItemAttr too long (%u) - skipping",
+ (unsigned int)attributes->attr[1].length);
+ goto skip;
+ }
+ if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
+ {
+ debug("kSecAccountItemAttr too long (%u) - skipping",
+ (unsigned int)attributes->attr[2].length);
+ goto skip;
+ }
+ if (attributes->attr[1].length >= sizeof(dnsprefix)-1 &&
+ 0 == strncasecmp(attributes->attr[1].data, dnsprefix,
+ sizeof(dnsprefix)-1))
+ format = formatDnsPrefixedServiceItem;
+ else if (attributes->attr[0].length == sizeof(ddns)-1 &&
+ 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
+ format = formatDdnsTypeItem;
+ else if (attributes->attr[0].length == sizeof(ddnsrev)-1 &&
+ 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
+ format = formatDdnsTypeItem;
+ else
+ {
+ debug("uninterested in this entry");
+ goto skip;
+ }
+ *attributesp = attributes;
+ debug("accepting this entry");
+ return format;
+
+skip:
+ SecKeychainItemFreeAttributesAndData(attributes, NULL);
+ return formatNotDNSKey;
+ }
+
+static CFPropertyListRef
+getKeychainItemInfo(SecKeychainItemRef item,
+ SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
+ {
+ CFMutableArrayRef entry = NULL;
+ CFDataRef data = NULL;
+ OSStatus status = noErr;
+ UInt32 keylen = 0;
+ void *keyp = 0;
+
+ if (NULL == (entry = CFArrayCreateMutable(NULL, 0,
+ &kCFTypeArrayCallBacks)))
+ {
+ debug("CFArrayCreateMutable failed");
+ goto error;
+ }
+ switch ((enum DNSKeyFormat)format)
+ {
+ case formatDdnsTypeItem:
+ data = CFDataCreate(kCFAllocatorDefault,
+ attributes->attr[1].data, attributes->attr[1].length);
+ break;
+ case formatDnsPrefixedServiceItem:
+ data = CFDataCreate(kCFAllocatorDefault,
+ attributes->attr[1].data + sizeof(dnsprefix)-1,
+ attributes->attr[1].length - (sizeof(dnsprefix)-1));
+ default:
+ assert("unknown DNSKeyFormat value");
+ break;
+ }
+ if (NULL == data)
+ {
+ debug("CFDataCreate for attr[1] failed");
+ goto error;
+ }
+ CFArrayAppendValue(entry, data);
+ CFRelease(data);
+ if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
+ attributes->attr[2].data, attributes->attr[2].length)))
+ {
+ debug("CFDataCreate for attr[2] failed");
+ goto error;
+ }
+ CFArrayAppendValue(entry, data);
+ CFRelease(data);
+ if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL,
+ NULL, NULL, &keylen, &keyp)))
+ {
+ debug("could not retrieve key for \"%.*s\": %d",
+ (int)attributes->attr[1].length, attributes->attr[1].data,
+ status);
+ goto error;
+ }
+ data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
+ SecKeychainItemFreeAttributesAndData(NULL, keyp);
+ if (NULL == data)
+ {
+ debug("CFDataCreate for keyp failed");
+ goto error;
+ }
+ CFArrayAppendValue(entry, data);
+ CFRelease(data);
+ return entry;
+
+error:
+ if (NULL != entry)
+ CFRelease(entry);
+ return NULL;
+ }
+#endif
+
+kern_return_t
+do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets,
+ __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err,
+ __unused audit_token_t token)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ CFWriteStreamRef stream = NULL;
+ CFDataRef result = NULL;
+ CFPropertyListRef entry = NULL;
+ CFMutableArrayRef keys = NULL;
+ SecKeychainRef skc = NULL;
+ SecKeychainItemRef item = NULL;
+ SecKeychainSearchRef search = NULL;
+ SecKeychainAttributeList *attributes = NULL;
+ enum DNSKeyFormat format;
+ OSStatus status = 0;
+
+ debug("entry");
+ *err = 0;
+ *numsecrets = 0;
+ *secrets = (vm_offset_t)NULL;
+ if (!authorized(&token))
+ {
+ *err = kmDNSHelperNotAuthorized;
+ goto fin;
+ }
+ if (NULL == (keys = CFArrayCreateMutable(NULL, 0,
+ &kCFTypeArrayCallBacks)))
+ {
+ debug("CFArrayCreateMutable failed");
+ *err = kmDNSHelperCreationFailed;
+ goto fin;
+ }
+ if (noErr != (status = SecKeychainCopyDefault(&skc)))
+ {
+ *err = kmDNSHelperKeychainCopyDefaultFailed;
+ goto fin;
+ }
+ if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
+ {
+ *err = kmDNSHelperKeychainSearchCreationFailed;
+ goto fin;
+ }
+ for (status = SecKeychainSearchCopyNext(search, &item);
+ noErr == status;
+ status = SecKeychainSearchCopyNext(search, &item))
+ {
+ if (formatNotDNSKey != (format = getDNSKeyFormat(item,
+ &attributes)) &&
+ NULL != (entry = getKeychainItemInfo(item, attributes,
+ format)))
+ {
+ CFArrayAppendValue(keys, entry);
+ CFRelease(entry);
+ }
+ SecKeychainItemFreeAttributesAndData(attributes, NULL);
+ CFRelease(item);
+ }
+ if (errSecItemNotFound != status)
+ helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d",
+ __func__, status);
+ if (NULL == (stream =
+ CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault,
+ kCFAllocatorDefault)))
+ {
+ *err = kmDNSHelperCreationFailed;
+ debug("CFWriteStreamCreateWithAllocatedBuffers failed");
+ goto fin;
+ }
+ CFWriteStreamOpen(stream);
+ if (0 == CFPropertyListWriteToStream(keys, stream,
+ kCFPropertyListBinaryFormat_v1_0, NULL))
+ {
+ *err = kmDNSHelperPListWriteFailed;
+ debug("CFPropertyListWriteToStream failed");
+ goto fin;
+ }
+ result = CFWriteStreamCopyProperty(stream,
+ kCFStreamPropertyDataWritten);
+ if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets,
+ CFDataGetLength(result), VM_FLAGS_ANYWHERE))
+ {
+ *err = kmDNSHelperCreationFailed;
+ debug("vm_allocate failed");
+ goto fin;
+ }
+ CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)),
+ (void *)*secrets);
+ *secretsCnt = CFDataGetLength(result);
+ *numsecrets = CFArrayGetCount(keys);
+ debug("succeeded");
+
+fin:
+ debug("returning %u secrets", *numsecrets);
+ if (NULL != stream)
+ {
+ CFWriteStreamClose(stream);
+ CFRelease(stream);
+ }
+ if (NULL != result)
+ CFRelease(result);
+ if (NULL != keys)
+ CFRelease(keys);
+ if (NULL != search)
+ CFRelease(search);
+ if (NULL != skc)
+ CFRelease(skc);
+ update_idle_timer();
+ return KERN_SUCCESS;
+#else
+ return KERN_FAILURE;
+#endif
+ }
+
+typedef enum _mDNSTunnelPolicyWhich
+ {
+ kmDNSTunnelPolicySetup,
+ kmDNSTunnelPolicyTeardown,
+ kmDNSTunnelPolicyGenerate
+ } mDNSTunnelPolicyWhich;
+
+static const uint8_t kWholeV6Mask = 128;
+static const uint8_t kZeroV6Mask = 0;
+
+static int
+doTunnelPolicy(mDNSTunnelPolicyWhich which,
+ v6addr_t loc_inner, uint8_t loc_bits,
+ v4addr_t loc_outer, uint16_t loc_port,
+ v6addr_t rmt_inner, uint8_t rmt_bits,
+ v4addr_t rmt_outer, uint16_t rmt_port);
+
+static int
+aliasTunnelAddress(v6addr_t address)
+ {
+ struct in6_aliasreq ifra_in6;
+ int err = 0;
+ int s = -1;
+
+ if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0)))
+ {
+ helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s",
+ strerror(errno));
+ err = kmDNSHelperDatagramSocketCreationFailed;
+ goto fin;
+ }
+ bzero(&ifra_in6, sizeof(ifra_in6));
+ strlcpy(ifra_in6.ifra_name, kTunnelAddressInterface,
+ sizeof(ifra_in6.ifra_name));
+ ifra_in6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+ ifra_in6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+
+ ifra_in6.ifra_addr.sin6_family = AF_INET6;
+ ifra_in6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
+ memcpy(&(ifra_in6.ifra_addr.sin6_addr), address,
+ sizeof(ifra_in6.ifra_addr.sin6_addr));
+
+ ifra_in6.ifra_prefixmask.sin6_family = AF_INET6;
+ ifra_in6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
+ memset(&(ifra_in6.ifra_prefixmask.sin6_addr), 0xFF,
+ sizeof(ifra_in6.ifra_prefixmask.sin6_addr));
+
+ if (0 > ioctl(s, SIOCAIFADDR_IN6, &ifra_in6))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s",
+ strerror(errno));
+ err = kmDNSHelperInterfaceCreationFailed;
+ goto fin;
+ }
+
+ v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+ err = doTunnelPolicy(kmDNSTunnelPolicyGenerate,
+ address, kWholeV6Mask, NULL, 0,
+ zero, kZeroV6Mask, NULL, 0);
+
+fin:
+ if (0 <= s)
+ close(s);
+ return err;
+ }
+
+static int
+unaliasTunnelAddress(v6addr_t address)
+ {
+ struct in6_ifreq ifr;
+ int err = 0;
+ int s = -1;
+
+ if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0)))
+ {
+ helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s",
+ strerror(errno));
+ err = kmDNSHelperDatagramSocketCreationFailed;
+ goto fin;
+ }
+ bzero(&ifr, sizeof(ifr));
+ strlcpy(ifr.ifr_name, kTunnelAddressInterface, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_addr.sin6_family = AF_INET6;
+ ifr.ifr_ifru.ifru_addr.sin6_len = sizeof(struct sockaddr_in6);
+ memcpy(&(ifr.ifr_ifru.ifru_addr.sin6_addr), address,
+ sizeof(ifr.ifr_ifru.ifru_addr.sin6_addr));
+
+ if (0 > ioctl(s, SIOCDIFADDR_IN6, &ifr))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s",
+ strerror(errno));
+ err = kmDNSHelperInterfaceDeletionFailed;
+ goto fin;
+ }
+
+ v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ err = doTunnelPolicy(kmDNSTunnelPolicyTeardown,
+ address, kWholeV6Mask, NULL, 0,
+ zero, kZeroV6Mask, NULL, 0);
+
+fin:
+ if (0 <= s)
+ close(s);
+ return err;
+ }
+
+int
+do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown,
+ v6addr_t address, int *err, audit_token_t token)
+ {
+ debug("entry");
+ *err = 0;
+ if (!authorized(&token))
+ {
+ *err = kmDNSHelperNotAuthorized;
+ goto fin;
+ }
+ switch ((enum mDNSUpDown)updown)
+ {
+ case kmDNSUp:
+ *err = aliasTunnelAddress(address);
+ break;
+ case kmDNSDown:
+ *err = unaliasTunnelAddress(address);
+ break;
+ default:
+ *err = kmDNSHelperInvalidInterfaceState;
+ goto fin;
+ }
+ debug("succeeded");
+
+fin:
+ update_idle_timer();
+ return KERN_SUCCESS;
+ }
+
+static const char racoon_config_path[] = "/etc/racoon/remote/anonymous.conf";
+static const char racoon_config_path_orig[] = "/etc/racoon/remote/anonymous.conf.orig";
+
+static const char configHeader[] = "# BackToMyMac\n";
+
+static int IsFamiliarRacoonConfiguration()
+ {
+ int fd = open(racoon_config_path, O_RDONLY);
+ debug("entry");
+ if (0 > fd)
+ {
+ helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno));
+ return 0;
+ }
+ else
+ {
+ char header[sizeof(configHeader)] = {0};
+ ssize_t bytesRead = read(fd, header, sizeof(header)-1);
+ close(fd);
+ if (bytesRead != sizeof(header)-1) return 0;
+ return (0 == memcmp(header, configHeader, sizeof(header)-1));
+ }
+ }
+
+static void
+revertAnonymousRacoonConfiguration()
+ {
+ debug("entry");
+ if (!IsFamiliarRacoonConfiguration())
+ {
+ helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
+ return;
+ }
+
+ if (0 > rename(racoon_config_path_orig, racoon_config_path))
+ {
+ helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno));
+ helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, unlinking", racoon_config_path);
+ unlink(racoon_config_path);
+ }
+ }
+
+static int
+createAnonymousRacoonConfiguration(const char *keydata)
+ {
+ static const char config1[] =
+ "remote anonymous {\n"
+ " exchange_mode aggressive;\n"
+ " doi ipsec_doi;\n"
+ " situation identity_only;\n"
+ " verify_identifier off;\n"
+ " generate_policy on;\n"
+ " shared_secret use \"";
+ static const char config2[] =
+ "\";\n"
+ " nonce_size 16;\n"
+ " lifetime time 5 min;\n"
+ " initial_contact on;\n"
+ " support_proxy on;\n"
+ " nat_traversal force;\n"
+ " proposal_check claim;\n"
+ " proposal {\n"
+ " encryption_algorithm aes;\n"
+ " hash_algorithm sha1;\n"
+ " authentication_method pre_shared_key;\n"
+ " dh_group 2;\n"
+ " lifetime time 5 min;\n"
+ " }\n"
+ "}\n\n"
+ "sainfo anonymous { \n"
+ " pfs_group 2;\n"
+ " lifetime time 10 min;\n"
+ " encryption_algorithm aes;\n"
+ " authentication_algorithm hmac_sha1;\n"
+ " compression_algorithm deflate;\n"
+ "}\n";
+ char tmp_config_path[] =
+ "/etc/racoon/remote/tmp.XXXXXX";
+ int fd = mkstemp(tmp_config_path);
+
+ debug("entry");
+
+ if (0 > fd)
+ {
+ helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
+ tmp_config_path, strerror(errno));
+ return -1;
+ }
+ write(fd, configHeader, sizeof(configHeader)-1);
+ write(fd, config1, sizeof(config1)-1);
+ write(fd, keydata, strlen(keydata));
+ write(fd, config2, sizeof(config2)-1);
+ close(fd);
+
+ if (IsFamiliarRacoonConfiguration())
+ helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, will overwrite", racoon_config_path);
+ else if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later
+ helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno));
+ else
+ debug("successfully renamed \"%s\" \"%s\"", racoon_config_path, racoon_config_path_orig);
+
+ if (0 > rename(tmp_config_path, racoon_config_path))
+ {
+ unlink(tmp_config_path);
+ helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s",
+ tmp_config_path, racoon_config_path, strerror(errno));
+ revertAnonymousRacoonConfiguration();
+ return -1;
+ }
+
+ debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path);
+ return 0;
+ }
+
+static int
+notifyRacoon(void)
+ {
+ debug("entry");
+ static const char racoon_pid_path[] = "/var/run/racoon.pid";
+ char buf[] = "18446744073709551615"; /* largest 64-bit integer */
+ char *p = NULL;
+ ssize_t n = 0;
+ unsigned long m = 0;
+ int fd = open(racoon_pid_path, O_RDONLY);
+
+ if (0 > fd)
+ {
+ debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path,
+ strerror(errno));
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ n = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ if (1 > n)
+ {
+ debug("read of \"%s\" failed: %s", racoon_pid_path,
+ n == 0 ? "empty file" : strerror(errno));
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ buf[n] = '\0';
+ m = strtoul(buf, &p, 10);
+ if (*p != '\0' && !isspace(*p))
+ {
+ debug("invalid PID \"%s\" (around '%c')", buf, *p);
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ if (2 > m)
+ {
+ debug("refusing to kill PID %lu", m);
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ if (0 != kill(m, SIGHUP))
+ {
+ debug("Could not signal racoon (%lu): %s", m, strerror(errno));
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ debug("Sent SIGHUP to racoon (%lu)", m);
+ return 0;
+ }
+
+static int
+startRacoon(void)
+ {
+ debug("entry");
+ char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL };
+ ssize_t n = 0;
+ pid_t pid = 0;
+ int status = 0;
+
+ if (0 == (pid = fork()))
+ {
+ closefds(0);
+ execve(racoon_args[0], racoon_args, NULL);
+ helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s",
+ racoon_args[0], strerror(errno));
+ exit(2);
+ }
+ helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started",
+ (unsigned long)pid);
+ n = waitpid(pid, &status, 0);
+ if (-1 == n)
+ {
+ helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s",
+ strerror(errno));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ else if (pid != n)
+ {
+ helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d",
+ (int)n);
+ return kmDNSHelperRacoonStartFailed;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "racoon (pid=%lu) terminated due to signal %d",
+ (unsigned long)pid, WTERMSIG(status));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ else if (WIFSTOPPED(status))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "racoon (pid=%lu) has stopped due to signal %d",
+ (unsigned long)pid, WSTOPSIG(status));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ else if (0 != WEXITSTATUS(status))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "racoon (pid=%lu) exited with status %d",
+ (unsigned long)pid, WEXITSTATUS(status));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid);
+ return 0;
+ }
+
+static int
+kickRacoon(void)
+ {
+ if ( 0 == notifyRacoon() )
+ return 0;
+ return startRacoon();
+ }
+
+int
+do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydata, int *err, audit_token_t token)
+ {
+ debug("entry");
+ *err = 0;
+
+ if (!authorized(&token))
+ {
+ *err = kmDNSHelperNotAuthorized;
+ goto fin;
+ }
+
+ switch ((enum mDNSUpDown)updown)
+ {
+ case kmDNSUp:
+ if (0 != createAnonymousRacoonConfiguration(keydata))
+ {
+ *err = kmDNSHelperRacoonConfigCreationFailed;
+ goto fin;
+ }
+ break;
+ case kmDNSDown:
+ revertAnonymousRacoonConfiguration();
+ break;
+ default:
+ *err = kmDNSHelperInvalidServerState;
+ goto fin;
+ }
+
+ if (0 != (*err = kickRacoon()))
+ goto fin;
+ debug("succeeded");
+
+fin:
+ update_idle_timer();
+ return KERN_SUCCESS;
+ }
+
+static unsigned int routeSeq = 1;
+
+static int
+setupTunnelRoute(v6addr_t local, v6addr_t remote)
+ {
+ struct
+ {
+ struct rt_msghdr hdr;
+ struct sockaddr_in6 dst;
+ struct sockaddr_in6 gtwy;
+ } msg;
+ int err = 0;
+ int s = -1;
+
+ if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
+ {
+ helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
+ strerror(errno));
+ err = kmDNSHelperRoutingSocketCreationFailed;
+ goto fin;
+ }
+ memset(&msg, 0, sizeof(msg));
+ msg.hdr.rtm_msglen = sizeof(msg);
+ msg.hdr.rtm_type = RTM_ADD;
+ /* The following flags are set by `route add -inet6 -host ...` */
+ msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC;
+ msg.hdr.rtm_version = RTM_VERSION;
+ msg.hdr.rtm_seq = routeSeq++;
+ msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ msg.hdr.rtm_inits = RTV_MTU;
+ msg.hdr.rtm_rmx.rmx_mtu = 1280;
+
+ msg.dst.sin6_len = sizeof(msg.dst);
+ msg.dst.sin6_family = AF_INET6;
+ memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
+
+ msg.gtwy.sin6_len = sizeof(msg.gtwy);
+ msg.gtwy.sin6_family = AF_INET6;
+ memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr));
+
+ /* send message, ignore error when route already exists */
+ if (0 > write(s, &msg, msg.hdr.rtm_msglen))
+ {
+ int errno_ = errno;
+
+ debug("write to routing socket failed: %s", strerror(errno_));
+ if (EEXIST != errno_)
+ {
+ err = kmDNSHelperRouteAdditionFailed;
+ goto fin;
+ }
+ }
+
+fin:
+ if (0 <= s)
+ close(s);
+ return err;
+ }
+
+static int
+teardownTunnelRoute(v6addr_t remote)
+ {
+ struct
+ {
+ struct rt_msghdr hdr;
+ struct sockaddr_in6 dst;
+ } msg;
+ int err = 0;
+ int s = -1;
+
+ if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
+ {
+ helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
+ strerror(errno));
+ err = kmDNSHelperRoutingSocketCreationFailed;
+ goto fin;
+ }
+ memset(&msg, 0, sizeof(msg));
+
+ msg.hdr.rtm_msglen = sizeof(msg);
+ msg.hdr.rtm_type = RTM_DELETE;
+ msg.hdr.rtm_version = RTM_VERSION;
+ msg.hdr.rtm_seq = routeSeq++;
+ msg.hdr.rtm_addrs = RTA_DST;
+
+ msg.dst.sin6_len = sizeof(msg.dst);
+ msg.dst.sin6_family = AF_INET6;
+ memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
+ if (0 > write(s, &msg, msg.hdr.rtm_msglen))
+ {
+ int errno_ = errno;
+
+ debug("write to routing socket failed: %s", strerror(errno_));
+ if (ESRCH != errno_)
+ {
+ err = kmDNSHelperRouteDeletionFailed;
+ goto fin;
+ }
+ }
+
+fin:
+ if (0 <= s)
+ close(s);
+ return err;
+ }
+
+static int
+v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
+ {
+ if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
+ {
+ helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
+ strerror(errno));
+ return kmDNSHelperInvalidNetworkAddress;
+ }
+ else
+ return 0;
+ }
+
+static int
+v6addr_to_string(v6addr_t addr, char *buf, size_t buflen)
+ {
+ if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
+ {
+ helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
+ strerror(errno));
+ return kmDNSHelperInvalidNetworkAddress;
+ }
+ else
+ return 0;
+ }
+
+/* Caller owns object returned in `policy' */
+static int
+generateTunnelPolicy(mDNSTunnelPolicyWhich which, int in,
+ v4addr_t src, uint16_t src_port,
+ v4addr_t dst, uint16_t dst_port,
+ ipsec_policy_t *policy, size_t *len)
+ {
+ char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
+ char buf[128];
+ char *inOut = in ? "in" : "out";
+ ssize_t n = 0;
+ int err = 0;
+
+ *policy = NULL;
+ *len = 0;
+
+ switch (which)
+ {
+ case kmDNSTunnelPolicySetup:
+ if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
+ goto fin;
+ if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
+ goto fin;
+ n = snprintf(buf, sizeof(buf),
+ "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
+ inOut, srcs, src_port, dsts, dst_port);
+ break;
+ case kmDNSTunnelPolicyTeardown:
+ n = strlcpy(buf, inOut, sizeof(buf));
+ break;
+ case kmDNSTunnelPolicyGenerate:
+ n = snprintf(buf, sizeof(buf), "%s generate", inOut);
+ break;
+ default:
+ err = kmDNSHelperIPsecPolicyCreationFailed;
+ goto fin;
+ }
+
+ if (n >= (int)sizeof(buf))
+ {
+ err = kmDNSHelperResultTooLarge;
+ goto fin;
+ }
+
+ debug("policy=\"%s\"", buf);
+ if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "Could not create IPsec policy from \"%s\"", buf);
+ err = kmDNSHelperIPsecPolicyCreationFailed;
+ goto fin;
+ }
+ *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
+
+fin:
+ return err;
+ }
+
+static int
+sendPolicy(int s, int setup,
+ struct sockaddr *src, uint8_t src_bits,
+ struct sockaddr *dst, uint8_t dst_bits,
+ ipsec_policy_t policy, size_t len)
+ {
+ static unsigned int policySeq = 0;
+ int err = 0;
+
+ debug("entry, setup=%d", setup);
+ if (setup)
+ err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
+ (char *)policy, len, policySeq++);
+ else
+ err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
+ (char *)policy, len, policySeq++);
+ if (0 > err)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s",
+ ipsec_strerror());
+ err = kmDNSHelperIPsecPolicySetFailed;
+ goto fin;
+ }
+ else
+ err = 0;
+ debug("succeeded");
+
+fin:
+ return err;
+ }
+
+static int
+removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
+ {
+ int err = 0;
+
+ debug("entry");
+ err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
+ if (0 > err)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
+ err = kmDNSHelperIPsecRemoveSAFailed;
+ goto fin;
+ }
+ err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
+ if (0 > err)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
+ err = kmDNSHelperIPsecRemoveSAFailed;
+ goto fin;
+ }
+ else
+ err = 0;
+
+ debug("succeeded");
+
+fin:
+ return err;
+ }
+
+static int
+doTunnelPolicy(mDNSTunnelPolicyWhich which,
+ v6addr_t loc_inner, uint8_t loc_bits,
+ v4addr_t loc_outer, uint16_t loc_port,
+ v6addr_t rmt_inner, uint8_t rmt_bits,
+ v4addr_t rmt_outer, uint16_t rmt_port)
+ {
+ struct sockaddr_in6 sin_loc;
+ struct sockaddr_in6 sin_rmt;
+ ipsec_policy_t policy = NULL;
+ size_t len = 0;
+ int s = -1;
+ int err = 0;
+
+ debug("entry");
+ if (0 > (s = pfkey_open()))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "Could not create IPsec policy socket: %s",
+ ipsec_strerror());
+ err = kmDNSHelperIPsecPolicySocketCreationFailed;
+ goto fin;
+ }
+
+ memset(&sin_loc, 0, sizeof(sin_loc));
+ sin_loc.sin6_len = sizeof(sin_loc);
+ sin_loc.sin6_family = AF_INET6;
+ sin_loc.sin6_port = htons(0);
+ memcpy(&sin_loc.sin6_addr, loc_inner, sizeof(sin_loc.sin6_addr));
+
+ memset(&sin_rmt, 0, sizeof(sin_rmt));
+ sin_rmt.sin6_len = sizeof(sin_rmt);
+ sin_rmt.sin6_family = AF_INET6;
+ sin_rmt.sin6_port = htons(0);
+ memcpy(&sin_rmt.sin6_addr, rmt_inner, sizeof(sin_rmt.sin6_addr));
+
+ int setup = which != kmDNSTunnelPolicyTeardown;
+
+ if (0 != (err = generateTunnelPolicy(which, 1,
+ rmt_outer, rmt_port,
+ loc_outer, loc_port,
+ &policy, &len)))
+ goto fin;
+ if (0 != (err = sendPolicy(s, setup,
+ (struct sockaddr *)&sin_rmt, rmt_bits,
+ (struct sockaddr *)&sin_loc, loc_bits,
+ policy, len)))
+ goto fin;
+ if (NULL != policy)
+ {
+ free(policy);
+ policy = NULL;
+ }
+ if (0 != (err = generateTunnelPolicy(which, 0,
+ loc_outer, loc_port,
+ rmt_outer, rmt_port,
+ &policy, &len)))
+ goto fin;
+ if (0 != (err = sendPolicy(s, setup,
+ (struct sockaddr *)&sin_loc, loc_bits,
+ (struct sockaddr *)&sin_rmt, rmt_bits,
+ policy, len)))
+ goto fin;
+
+ if (which == kmDNSTunnelPolicyTeardown && loc_outer && rmt_outer)
+ {
+ struct sockaddr_in sin_loc;
+ struct sockaddr_in sin_rmt;
+
+ memset(&sin_loc, 0, sizeof(sin_loc));
+ sin_loc.sin_len = sizeof(sin_loc);
+ sin_loc.sin_family = AF_INET;
+ sin_loc.sin_port = htons(0);
+ memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
+
+ memset(&sin_rmt, 0, sizeof(sin_rmt));
+ sin_rmt.sin_len = sizeof(sin_rmt);
+ sin_rmt.sin_family = AF_INET;
+ sin_rmt.sin_port = htons(0);
+ memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
+
+ if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
+ goto fin;
+ }
+
+ debug("succeeded");
+
+fin:
+ if (0 >= s)
+ close(s);
+ if (NULL != policy)
+ free(policy);
+ return err;
+ }
+
+int
+do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
+ v6addr_t loc_inner, v4addr_t loc_outer, uint16_t loc_port,
+ v6addr_t rmt_inner, v4addr_t rmt_outer, uint16_t rmt_port,
+ const char *keydata, int *err, audit_token_t token)
+ {
+ static const char config[] =
+ "%s"
+ "remote %s [%u] {\n"
+ " exchange_mode aggressive;\n"
+ " doi ipsec_doi;\n"
+ " situation identity_only;\n"
+ " verify_identifier off;\n"
+ " generate_policy on;\n"
+ " shared_secret use \"%s\";\n"
+ " nonce_size 16;\n"
+ " lifetime time 5 min;\n"
+ " initial_contact on;\n"
+ " support_proxy on;\n"
+ " nat_traversal force;\n"
+ " proposal_check claim;\n"
+ " proposal {\n"
+ " encryption_algorithm aes;\n"
+ " hash_algorithm sha1;\n"
+ " authentication_method pre_shared_key;\n"
+ " dh_group 2;\n"
+ " lifetime time 5 min;\n"
+ " }\n"
+ "}\n\n"
+ "sainfo address %s any address %s any {\n"
+ " pfs_group 2;\n"
+ " lifetime time 10 min;\n"
+ " encryption_algorithm aes;\n"
+ " authentication_algorithm hmac_sha1;\n"
+ " compression_algorithm deflate;\n"
+ "}\n\n"
+ "sainfo address %s any address %s any {\n"
+ " pfs_group 2;\n"
+ " lifetime time 10 min;\n"
+ " encryption_algorithm aes;\n"
+ " authentication_algorithm hmac_sha1;\n"
+ " compression_algorithm deflate;\n"
+ "}\n";
+ char path[PATH_MAX] = "";
+ char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN],
+ ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN];
+ FILE *fp = NULL;
+ int fd = -1;
+ char tmp_path[PATH_MAX] = "";
+
+ debug("entry");
+ *err = 0;
+ if (!authorized(&token))
+ {
+ *err = kmDNSHelperNotAuthorized;
+ goto fin;
+ }
+ switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
+ {
+ case kmDNSAutoTunnelSetKeysReplace:
+ case kmDNSAutoTunnelSetKeysDelete:
+ break;
+ default:
+ *err = kmDNSHelperInvalidTunnelSetKeysOperation;
+ goto fin;
+ }
+ if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
+ goto fin;
+ if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
+ goto fin;
+ if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
+ goto fin;
+ if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
+ goto fin;
+ debug("loc_inner=%s rmt_inner=%s", li, ri);
+ debug("loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
+ lo, loc_port, ro, rmt_port);
+
+ if ((int)sizeof(path) <= snprintf(path, sizeof(path),
+ "/etc/racoon/remote/%s.%u.conf", ro,
+ rmt_port))
+ {
+ *err = kmDNSHelperResultTooLarge;
+ goto fin;
+ }
+ if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
+ {
+ if ((int)sizeof(tmp_path) <=
+ snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
+ {
+ *err = kmDNSHelperResultTooLarge;
+ goto fin;
+ }
+ if (0 > (fd = mkstemp(tmp_path)))
+ {
+ helplog(ASL_LEVEL_ERR, "mktemp \"%s\" failed: %s",
+ tmp_path, strerror(errno));
+ *err = kmDNSHelperRacoonConfigCreationFailed;
+ goto fin;
+ }
+ if (NULL == (fp = fdopen(fd, "w")))
+ {
+ helplog(ASL_LEVEL_ERR, "fdopen: %s",
+ strerror(errno));
+ *err = kmDNSHelperRacoonConfigCreationFailed;
+ goto fin;
+ }
+ fd = -1;
+ fprintf(fp, config, configHeader, ro, rmt_port, keydata, ri, li, li, ri);
+ fclose(fp);
+ fp = NULL;
+ if (0 > rename(tmp_path, path))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "rename \"%s\" \"%s\" failed: %s",
+ tmp_path, path, strerror(errno));
+ *err = kmDNSHelperRacoonConfigCreationFailed;
+ goto fin;
+ }
+ if (0 != (*err = kickRacoon()))
+ goto fin;
+ }
+ else
+ {
+ if (0 != unlink(path))
+ debug("unlink \"%s\" failed: %s", path,
+ strerror(errno));
+ }
+
+ if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown,
+ loc_inner, kWholeV6Mask, loc_outer, loc_port,
+ rmt_inner, kWholeV6Mask, rmt_outer, rmt_port)))
+ goto fin;
+ if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+ 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup,
+ loc_inner, kWholeV6Mask, loc_outer, loc_port,
+ rmt_inner, kWholeV6Mask, rmt_outer, rmt_port)))
+ goto fin;
+
+ if (0 != (*err = teardownTunnelRoute(rmt_inner)))
+ goto fin;
+ if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+ 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
+ goto fin;
+
+ debug("succeeded");
+
+fin:
+ if (NULL != fp)
+ fclose(fp);
+ if (0 <= fd)
+ close(fd);
+ unlink(tmp_path);
+ update_idle_timer();
+ return KERN_SUCCESS;
+ }
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: helper.h,v $
+Revision 1.6 2007/09/20 22:33:17 cheshire
+Tidied up inconsistent and error-prone naming -- used to be mDNSResponderHelper in
+some places and mDNSResponder.helper in others; now mDNSResponderHelper everywhere
+
+Revision 1.5 2007/09/07 22:44:03 mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.4 2007/09/04 22:32:58 mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.3 2007/08/23 21:51:44 cheshire
+Made code layout style consistent with existing project style; added $Log header
+
+Revision 1.1 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#ifndef H_HELPER_H
+#define H_HELPER_H
+
+#define kmDNSHelperServiceName "com.apple.mDNSResponderHelper"
+
+enum mDNSDynamicStoreSetConfigKey
+ {
+ kmDNSMulticastConfig = 1,
+ kmDNSDynamicConfig,
+ kmDNSPrivateConfig,
+ kmDNSBackToMyMacConfig
+ };
+
+enum mDNSPreferencesSetNameKey
+ {
+ kmDNSComputerName = 1,
+ kmDNSLocalHostName
+ };
+
+enum mDNSUpDown
+ {
+ kmDNSUp = 1,
+ kmDNSDown
+ };
+
+enum mDNSAutoTunnelSetKeysReplaceDelete
+ {
+ kmDNSAutoTunnelSetKeysReplace = 1,
+ kmDNSAutoTunnelSetKeysDelete
+ };
+
+#define ERROR(x, y) x,
+enum mDNSHelperErrors
+ {
+ mDNSHelperErrorBase = 2300,
+ #include "helper-error.h"
+ mDNSHelperErrorEnd
+ };
+#undef ERROR
+
+#include "mDNSEmbeddedAPI.h"
+#include "helpermsg-types.h"
+
+extern const char *mDNSHelperError(int errornum);
+extern int mDNSPreferencesSetName(int key, domainlabel* old, domainlabel* new);
+extern int mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value);
+extern int mDNSKeychainGetSecrets(CFArrayRef *secrets);
+extern int mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t addr);
+extern int mDNSConfigureServer(int updown, const char *keydata);
+extern int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
+ v4addr_t local_outer, short local_port, v6addr_t remote_inner,
+ v4addr_t remote_outer, short remote_port, const char *keydata);
+
+#endif /* H_HELPER_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: helpermsg-types.h,v $
+Revision 1.2 2007/08/23 21:52:19 cheshire
+Added License header
+
+Revision 1.1 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#ifndef H_HELPERMSG_TYPES_H
+#define H_HELPERMSG_TYPES_H
+
+#include <stdint.h>
+typedef uint8_t v6addr_t[16];
+typedef uint8_t v4addr_t[4];
+typedef const char *string_t;
+
+#endif /* H_HELPERMSG_TYPES_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: helpermsg.defs,v $
+Revision 1.6 2007/09/07 22:44:03 mcguire
+<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
+
+Revision 1.5 2007/09/04 22:32:58 mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+
+Revision 1.4 2007/08/23 21:53:13 cheshire
+Added $Log header
+
+Revision 1.3 2007/08/18 01:02:03 mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.2 2007/08/15 23:20:28 mcguire
+<rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
+
+Revision 1.1 2007/08/08 22:34:58 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+ */
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+import "helpermsg-types.h";
+
+type v6addr_t = array [16] of uint8_t;
+type v4addr_t = array [4] of uint8_t;
+type string_t = c_string[*:1024];
+
+subsystem helper 1833193043;
+serverprefix do_;
+userprefix proxy_;
+
+simpleroutine mDNSIdleExit(
+ port : mach_port_t;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSDynamicStoreSetConfig(
+ port : mach_port_t;
+ key : int;
+ value : pointer_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSPreferencesSetName(
+ port : mach_port_t;
+ key : int;
+ old : string_t;
+ new : string_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSKeychainGetSecrets(
+ port : mach_port_t;
+ out numsecrets : unsigned;
+ out secrets : pointer_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSAutoTunnelInterfaceUpDown(
+ port : mach_port_t;
+ updown : int;
+ address : v6addr_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSConfigureServer(
+ port : mach_port_t;
+ updown : int;
+ keydata : string_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSAutoTunnelSetKeys(
+ port : mach_port_t;
+ replacedelete : int;
+ local_inner : v6addr_t;
+ local_outer : v4addr_t;
+ local_port : uint16_t;
+ remote_inner : v6addr_t;
+ remote_outer : v4addr_t;
+ remote_port : uint16_t;
+ keydata : string_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
--- /dev/null
+/*
+ * Copyright (c) 2003-2007 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* $FreeBSD: src/lib/libipsec/ipsec_strerror.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
+/* $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+extern int __ipsec_errcode;
+extern void __ipsec_set_strerror __P((const char *));
+
+#define EIPSEC_NO_ERROR 0 /*success*/
+#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/
+#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/
+#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/
+#define EIPSEC_INVAL_VERSION 4 /*invalid version*/
+#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/
+#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/
+#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/
+#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/
+#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/
+#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/
+#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/
+#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/
+#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/
+#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/
+#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/
+#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/
+#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/
+#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/
+#define EIPSEC_NO_PROTO 19 /*no protocol specified*/
+#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/
+#define EIPSEC_NO_BUFS 21 /*no buffers available*/
+#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/
+#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/
+#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/
+#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/
+#define EIPSEC_SYSTEM_ERROR 26 /*system error*/
+#define EIPSEC_MAX 27 /*unknown error*/
--- /dev/null
+/*
+ * Copyright (c) 2003-2007 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* $FreeBSD: src/lib/libipsec/libpfkey.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
+/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+struct sadb_msg;
+extern void pfkey_sadump __P((struct sadb_msg *));
+extern void pfkey_spdump __P((struct sadb_msg *));
+
+struct sockaddr;
+struct sadb_alg;
+int ipsec_check_keylen __P((u_int, u_int, u_int));
+int ipsec_check_keylen2 __P((u_int, u_int, u_int));
+int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *));
+u_int pfkey_set_softrate __P((u_int, u_int));
+u_int pfkey_get_softrate __P((u_int));
+int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t));
+int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int,
+ caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+ u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int,
+ caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+ u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_delete __P((int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_delete_all __P((int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *));
+int pfkey_send_get __P((int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_register __P((int, u_int));
+int pfkey_recv_register __P((int));
+int pfkey_set_supported __P((struct sadb_msg *, int));
+int pfkey_send_flush __P((int, u_int));
+int pfkey_send_dump __P((int, u_int));
+int pfkey_send_promisc_toggle __P((int, int));
+int pfkey_send_spdadd __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+ caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+ caddr_t, int, u_int32_t));
+int pfkey_send_spddelete __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spddelete2 __P((int, u_int32_t));
+int pfkey_send_spdget __P((int, u_int32_t));
+int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdflush __P((int));
+int pfkey_send_spddump __P((int));
+
+int pfkey_open __P((void));
+void pfkey_close __P((int));
+struct sadb_msg *pfkey_recv __P((int));
+int pfkey_send __P((int, struct sadb_msg *, int));
+int pfkey_align __P((struct sadb_msg *, caddr_t *));
+int pfkey_check __P((caddr_t *));
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSMacOSX.c,v $
-Revision 1.318.2.3 2007/07/18 20:35:42 cheshire
-Bracket LegacyNATInit/LegacyNATDestroy calls with "#ifdef _LEGACY_NAT_TRAVERSAL_"
-
-Revision 1.318.2.2 2006/12/14 21:38:51 cheshire
-Fix problem exposed by previous changes: kSecAccountItemAttr is not necessarily nul-terminated
-
-Revision 1.318.2.1 2006/10/31 02:37:04 cheshire
-<rdar://problem/4779534> Stop creating HINFO records
-
-Revision 1.318 2005/10/20 00:10:34 cheshire
-<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
-
-Revision 1.317 2005/09/24 01:10:26 cheshire
-Fix comment typos
-
-Revision 1.316 2005/07/29 18:04:22 ksekar
-<rdar://problem/4137930> Hostname registration should register IPv6 AAAA record with DNS Update
-
-Revision 1.315 2005/07/22 21:50:55 ksekar
-Fix GCC 4.0/Intel compiler warnings
-
-Revision 1.314 2005/07/11 02:12:09 cheshire
-<rdar://problem/4147774> Be defensive against invalid UTF-8 in dynamic host names
-Fix copy-and-paste error: "CFRelease(StatusVals[0]);" should be "CFRelease(StateVals[0]);"
-
-Revision 1.313 2005/07/04 23:52:25 cheshire
-<rdar://problem/3923098> Things are showing up with a bogus interface index
-
-Revision 1.312 2005/07/04 22:24:36 cheshire
-Export NotifyOfElusiveBug() so other files can call it
-
-Revision 1.311 2005/06/15 13:20:43 cheshire
-<rdar://problem/4147774> Be defensive against invalid UTF-8 in dynamic host names
-
-Revision 1.310 2005/04/07 00:49:58 cheshire
-<rdar://problem/4080074> PPP connection disables Bonjour ".local" lookups
-
-Revision 1.309 2005/03/23 05:53:29 cheshire
-Fix %s where it should have been %##s in debugf & LogMsg calls
-
-Revision 1.308 2005/03/09 00:48:44 cheshire
-<rdar://problem/4015157> QU packets getting sent too early on wake from sleep
-Move "m->p->NetworkChanged = 0;" line from caller to callee
-
-Revision 1.307 2005/03/03 03:12:02 cheshire
-Add comment about mDNSMacOSXSystemBuildNumber()
-
-Revision 1.306 2005/03/02 22:18:00 cheshire
-<rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
-
-Revision 1.305 2005/02/26 05:08:28 cheshire
-<rdar://problem/3930171> mDNSResponder requires AppleInternal packages to build on Tiger
-Added dnsinfo.h to project directory
-
-Revision 1.304 2005/02/25 23:51:22 cheshire
-<rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
-Return mStatus_UnknownErr instead of -1
-
-Revision 1.303 2005/02/25 17:47:45 ksekar
-<rdar://problem/4021868> SendServiceRegistration fails on wake from sleep
-
-Revision 1.302 2005/02/25 02:34:14 cheshire
-<rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
-Show status as 1 (in progress) while we're trying
-
-Revision 1.301 2005/02/24 21:55:57 ksekar
-<rdar://problem/4017292> Should not indicate successful dynamic update if no network connection
-
-Revision 1.300 2005/02/15 20:03:13 ksekar
-<rdar://problem/4005868> Crash when SCPreferences contains empty array
-
-Revision 1.299 2005/02/15 02:46:53 cheshire
-<rdar://problem/3967876> Don't log ENETUNREACH errors for unicast destinations
-
-Revision 1.298 2005/02/10 00:41:59 cheshire
-Fix compiler warning
-
-Revision 1.297 2005/02/09 23:38:51 ksekar
-<rdar://problem/3993508> Reregister hostname when DNS server changes but IP address does not
-
-Revision 1.296 2005/02/01 21:06:52 ksekar
-Avoid spurious log message
-
-Revision 1.295 2005/02/01 19:33:30 ksekar
-<rdar://problem/3985239> Keychain format too restrictive
-
-Revision 1.294 2005/01/27 21:30:23 cheshire
-<rdar://problem/3952067> "Can't assign requested address" message after AirPort turned off
-Don't write syslog messages for EADDRNOTAVAIL if we know network configuration changes are happening
-
-Revision 1.293 2005/01/27 19:15:41 cheshire
-Remove extraneous LogMsg() call
-
-Revision 1.292 2005/01/27 17:48:38 cheshire
-Added comment about CFSocketInvalidate closing the underlying socket
-
-Revision 1.291 2005/01/27 00:10:58 cheshire
-<rdar://problem/3967867> Name change log messages every time machine boots
-
-Revision 1.290 2005/01/25 23:18:30 ksekar
-fix for <rdar://problem/3971467> requires that local-only ".local" registration record be created
-
-Revision 1.289 2005/01/25 18:08:31 ksekar
-Removed redundant debug output
-
-Revision 1.288 2005/01/25 17:42:26 ksekar
-Renamed FoundDefBrowseDomain -> FoundLegacyBrowseDomain,
-cleaned up duplicate log messages when adding/removing browse domains
-
-Revision 1.287 2005/01/25 16:59:23 ksekar
-<rdar://problem/3971138> sa_len not set checking reachability for TCP connections
-
-Revision 1.286 2005/01/25 02:02:37 cheshire
-<rdar://problem/3970673> mDNSResponder leaks
-GetSearchDomains() was not calling dns_configuration_free().
-
-Revision 1.285 2005/01/22 00:07:54 ksekar
-<rdar://problem/3960546> mDNSResponder should look at all browse domains in SCPreferences
-
-Revision 1.284 2005/01/21 23:07:17 ksekar
-<rdar://problem/3960795> mDNSResponder causes Dial on Demand
-
-Revision 1.283 2005/01/19 21:16:16 cheshire
-Make sure when we set NetworkChanged that we don't set it to zero
-
-Revision 1.282 2005/01/19 19:19:21 ksekar
-<rdar://problem/3960191> Need a way to turn off domain discovery
-
-Revision 1.281 2005/01/18 18:10:55 ksekar
-<rdar://problem/3954575> Use 10.4 resolver API to get search domains
-
-Revision 1.280 2005/01/17 22:48:52 ksekar
-No longer need to call MarkSearchListElem for registration domain
-
-Revision 1.279 2005/01/17 20:40:34 ksekar
-SCPreferences changes should remove exactly one browse and one legacy browse domain for each remove event
-
-Revision 1.278 2005/01/17 19:53:34 ksekar
-Refinement to previous fix - register _legacy._browse records for SCPreference domains to achieve correct reference counting
-
-Revision 1.277 2005/01/12 00:17:50 ksekar
-<rdar://problem/3933573> Update LLQs *after* setting DNS
-
-Revision 1.276 2005/01/10 17:39:10 ksekar
-Refinement to 1.272 - avoid spurious warnings when registration and browse domains are set to same value and toggled on/off
-
-Revision 1.275 2005/01/10 04:02:22 ksekar
-Refinement to <rdar://problem/3891628> - strip trailing dot before writing hostname status to dynamic store
-
-Revision 1.274 2005/01/10 03:41:36 ksekar
-Correction to checkin 1.272 - check that registration domain is set
-before trying to remove it as an implicit browse domain
-
-Revision 1.273 2005/01/08 00:42:18 ksekar
-<rdar://problem/3922758> Clean up syslog messages
-
-Revision 1.272 2005/01/07 23:21:42 ksekar
-<rdar://problem/3891628> Clean up SCPreferences format
-
-Revision 1.271 2004/12/20 23:18:12 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-One more refinement: When an interface with a v6LL address gets a v4 address too, that's not a flap
-
-Revision 1.270 2004/12/20 21:28:14 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-Additional refinements to handle sleep/wake better
-
-Revision 1.269 2004/12/20 20:48:11 cheshire
-Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
-
-Revision 1.268 2004/12/18 03:19:04 cheshire
-Show netmask in error log
-
-Revision 1.267 2004/12/18 00:51:52 cheshire
-Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
-
-Revision 1.266 2004/12/17 23:49:38 cheshire
-<rdar://problem/3922754> Computer Name change is slow
-Also treat changes to "Setup:/Network/DynamicDNS" the same way
-
-Revision 1.265 2004/12/17 23:37:47 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.264 2004/12/17 19:03:05 cheshire
-Update debugging messages to show netmask a simple CIDR-style numeric value (0-128)
-
-Revision 1.263 2004/12/17 05:25:46 cheshire
-<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
-
-Revision 1.262 2004/12/17 04:48:32 cheshire
-<rdar://problem/3922754> Computer Name change is slow
-
-Revision 1.261 2004/12/17 02:40:08 cheshire
-Undo last change -- it was too strict
-
-Revision 1.260 2004/12/16 22:17:16 cheshire
-Only accept multicast packets on interfaces that have McastTxRx set
+Revision 1.496 2007/10/04 20:33:05 mcguire
+<rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
-Revision 1.259 2004/12/16 20:13:01 cheshire
-<rdar://problem/3324626> Cache memory management improvements
+Revision 1.495 2007/10/02 05:03:38 cheshire
+Fix bugus indentation in mDNSPlatformDynDNSHostNameStatusChanged
-Revision 1.258 2004/12/14 00:18:05 cheshire
-Don't log dns_configuration_copy() failures in the first three minutes after boot
+Revision 1.494 2007/09/29 20:40:19 cheshire
+<rdar://problem/5513378> Crash in ReissueBlockedQuestions
-Revision 1.257 2004/12/10 19:45:46 cheshire
-<rdar://problem/3915074> Reduce egregious stack space usage
-Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes
+Revision 1.493 2007/09/29 03:16:45 cheshire
+<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
+When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
-Revision 1.256 2004/12/10 04:35:43 cheshire
-<rdar://problem/3907233> Show "Note: Compiled without Apple-specific split DNS support" only once
+Revision 1.492 2007/09/28 23:58:35 mcguire
+<rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
+Fix locking issue.
-Revision 1.255 2004/12/10 04:12:54 ksekar
-<rdar://problem/3890764> Need new DefaultBrowseDomain key
+Revision 1.491 2007/09/27 23:28:53 mcguire
+<rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
-Revision 1.254 2004/12/10 01:55:31 ksekar
-<rdar://problem/3899067> Keychain lookups should be in lower case.
+Revision 1.490 2007/09/26 23:01:21 mcguire
+<rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
-Revision 1.253 2004/12/09 03:15:41 ksekar
-<rdar://problem/3806610> use _legacy instead of _default to find "empty string" browse domains
+Revision 1.489 2007/09/26 22:58:16 mcguire
+<rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
-Revision 1.252 2004/12/07 01:32:42 cheshire
-Don't log dns_configuration_copy() failure when running on 10.3
+Revision 1.488 2007/09/26 00:32:45 cheshire
+Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
-Revision 1.251 2004/12/06 22:30:31 cheshire
-Added debugging log message
+Revision 1.487 2007/09/21 17:07:41 mcguire
+<rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
-Revision 1.250 2004/12/06 06:59:08 ksekar
-RegisterSplitDNS should return Unsupported error when compiled on Panther
+Revision 1.486 2007/09/19 23:17:38 cheshire
+<rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
-Revision 1.249 2004/12/04 00:29:46 cheshire
-Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems
-(When compiled on 10.3, code will not include split-DNS support.)
+Revision 1.485 2007/09/19 21:44:29 cheshire
+Improved "mDNSKeychainGetSecrets failed" error message
-Revision 1.248 2004/12/01 20:57:20 ksekar
-<rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
+Revision 1.484 2007/09/18 21:44:55 cheshire
+<rdar://problem/5469006> Crash in GetAuthInfoForName_internal
+Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
-Revision 1.247 2004/12/01 03:26:58 cheshire
-Remove unused variables
+Revision 1.483 2007/09/17 22:19:39 mcguire
+<rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
+No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
-Revision 1.246 2004/12/01 01:51:34 cheshire
-Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
+Revision 1.482 2007/09/14 21:16:03 cheshire
+<rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
-Revision 1.245 2004/11/30 03:24:04 cheshire
-<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
+Revision 1.481 2007/09/14 21:14:56 mcguire
+<rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
-Revision 1.244 2004/11/30 02:59:35 cheshire
-For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls
+Revision 1.480 2007/09/13 00:16:42 cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-Revision 1.243 2004/11/29 19:17:29 ksekar
-<rdar://problem/3878195> Unnecessary GetUserSpecifiedDDNSConfig log messages
+Revision 1.479 2007/09/12 19:22:20 cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-Revision 1.242 2004/11/29 18:37:38 ksekar
-<rdar://problem/3889341> Buffer overflow in GetConfigOption
+Revision 1.478 2007/09/07 22:21:45 vazquez
+<rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
-Revision 1.241 2004/11/25 01:37:04 ksekar
-<rdar://problem/3894854> Config file and SCPreferences don't play well together
+Revision 1.477 2007/09/07 21:22:30 cheshire
+<rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
+Don't log failures binding to port 5351
-Revision 1.240 2004/11/25 01:29:42 ksekar
-Remove unnecessary log messages
+Revision 1.476 2007/09/06 20:38:08 cheshire
+<rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
-Revision 1.239 2004/11/25 01:27:19 ksekar
-<rdar://problem/3885859> Don't try to advertise link-local IP addresses via dynamic update
+Revision 1.475 2007/09/05 02:24:28 cheshire
+<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
+In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
-Revision 1.238 2004/11/24 22:00:59 cheshire
-Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h
+Revision 1.474 2007/09/04 22:32:58 mcguire
+<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
-Revision 1.237 2004/11/24 21:54:44 cheshire
-<rdar://problem/3894475> mDNSCore not receiving unicast responses properly
+Revision 1.473 2007/08/31 19:53:15 cheshire
+<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
+If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
-Revision 1.236 2004/11/23 03:39:46 cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
+Revision 1.472 2007/08/31 18:49:49 vazquez
+<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
-Revision 1.235 2004/11/17 01:45:35 cheshire
-<rdar://problem/3847435> mDNS buddy list frequently becomes empty if you let the machine sleep
-Refresh our interface list on receiving kIOMessageSystemHasPoweredOn,
-in case we get no System Configuration Framework "network changed" event.
+Revision 1.471 2007/08/31 02:05:46 cheshire
+Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
-Revision 1.234 2004/11/17 00:32:56 ksekar
-<rdar://problem/3880773> mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option
+Revision 1.470 2007/08/30 22:50:04 mcguire
+<rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
-Revision 1.233 2004/11/12 03:16:45 rpantos
-rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
+Revision 1.469 2007/08/30 19:40:51 cheshire
+Added syslog messages to report various initialization failures
-Revision 1.232 2004/11/10 20:40:54 ksekar
-<rdar://problem/3868216> LLQ mobility fragile on non-primary interface
+Revision 1.468 2007/08/30 00:12:20 cheshire
+Check error codes and log failures during AutoTunnel setup
-Revision 1.231 2004/11/06 00:59:33 ksekar
-Don't log ENETDOWN errors for unicast destinations (pollutes log on
-wake from sleep)
+Revision 1.467 2007/08/28 00:33:04 jgraessley
+<rdar://problem/5423932> Selective compilation options
-Revision 1.230 2004/11/05 01:04:10 ksekar
-<rdar://problem/3774577> LegacyNATDestroy() called too enthusiastically
+Revision 1.466 2007/08/24 23:25:55 cheshire
+Debugging messages to help track down duplicate items being read from system keychain
-Revision 1.229 2004/11/03 03:45:16 cheshire
-<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
+Revision 1.465 2007/08/24 00:39:12 cheshire
+Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
-Revision 1.228 2004/11/02 23:47:32 cheshire
-<rdar://problem/3863214> Default hostname and Computer Name should be unique
+Revision 1.464 2007/08/24 00:15:21 cheshire
+Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
-Revision 1.227 2004/11/02 04:23:03 cheshire
-Change to more informative name "GetUserSpecifiedLocalHostName()"
+Revision 1.463 2007/08/23 21:02:35 cheshire
+SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
-Revision 1.226 2004/11/01 20:36:19 ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
+Revision 1.462 2007/08/18 01:02:03 mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
-Revision 1.225 2004/10/28 19:03:04 cheshire
-Remove \n from LogMsg() calls
+Revision 1.461 2007/08/10 22:25:57 mkrochma
+<rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
-Revision 1.224 2004/10/28 17:47:34 cheshire
-Oops. Forgot the %d in the log message.
+Revision 1.460 2007/08/08 22:34:59 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-Revision 1.223 2004/10/28 17:24:28 cheshire
-Updated "bad ifa_netmask" log message to give more information
+Revision 1.459 2007/08/08 21:07:48 vazquez
+<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
-Revision 1.222 2004/10/28 03:36:34 cheshire
-<rdar://problem/3856535> Share the same port for both multicast and unicast receiving
+Revision 1.458 2007/08/03 02:18:41 mcguire
+<rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
-Revision 1.221 2004/10/28 03:24:41 cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
+Revision 1.457 2007/08/02 16:48:45 mcguire
+<rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
-Revision 1.220 2004/10/28 00:53:57 cheshire
-Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
-Add LogOperation() call to record when we get network change events
+Revision 1.456 2007/08/02 03:28:30 vazquez
+Make ExternalAddress and err unused to fix build warnings
-Revision 1.219 2004/10/27 20:42:20 cheshire
-Clean up debugging messages
+Revision 1.455 2007/08/01 03:09:22 cheshire
+<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
-Revision 1.218 2004/10/27 02:03:59 cheshire
-Update debugging messages
+Revision 1.454 2007/07/31 23:08:34 mcguire
+<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
-Revision 1.217 2004/10/26 20:48:21 cheshire
-Improve logging messages
+Revision 1.453 2007/07/31 19:13:58 mkrochma
+No longer need to include "btmm" in hostname to avoid name conflicts
-Revision 1.216 2004/10/26 01:02:37 cheshire
-Update comment
+Revision 1.452 2007/07/27 19:30:41 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
-Revision 1.215 2004/10/25 20:09:00 ksekar
-Cleaned up config file parsing.
+Revision 1.451 2007/07/25 22:25:45 cheshire
+<rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
-Revision 1.214 2004/10/25 19:30:53 ksekar
-<rdar://problem/3827956> Simplify dynamic host name structures
+Revision 1.450 2007/07/25 21:19:10 cheshire
+<rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
-Revision 1.213 2004/10/23 01:16:01 cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
+Revision 1.449 2007/07/25 01:36:09 mcguire
+<rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
-Revision 1.212 2004/10/22 20:52:08 ksekar
-<rdar://problem/3799260> Create NAT port mappings for Long Lived Queries
+Revision 1.448 2007/07/24 21:30:09 cheshire
+Added "AutoTunnel server listening for connections..." diagnostic message
-Revision 1.211 2004/10/22 01:07:11 cheshire
-<rdar://problem/3375328> select() says data is waiting; recvfrom() says there is no data
-Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr).
-These are all supposed to be remapped to /dev/null
+Revision 1.447 2007/07/24 20:24:18 cheshire
+Only remove AutoTunnel address if we have created it.
+Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
-Revision 1.210 2004/10/20 02:19:54 cheshire
-Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains()
+Revision 1.446 2007/07/24 03:00:09 cheshire
+SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
-Revision 1.209 2004/10/16 00:17:00 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.445 2007/07/23 20:26:26 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
+Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
+for existence of "Setup:/Network/DynamicDNS" settings
-Revision 1.208 2004/10/15 23:00:18 ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
+Revision 1.444 2007/07/21 00:54:49 cheshire
+<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
-Revision 1.207 2004/10/13 22:45:23 cheshire
-<rdar://problem/3438392> Ten-second delay before kIOMessageSystemHasPoweredOn message
+Revision 1.443 2007/07/20 23:23:11 cheshire
+Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
-Revision 1.206 2004/10/13 22:11:46 cheshire
-Update debugging messages
+Revision 1.442 2007/07/20 20:23:24 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
+Fixed errors reading the Setup:/Network/BackToMyMac preferences
-Revision 1.205 2004/10/12 21:10:11 cheshire
-<rdar://problem/3438376> mach_absolute_time() not monotonically increasing
-Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards
+Revision 1.441 2007/07/20 16:46:45 mcguire
+<rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
-Revision 1.204 2004/10/12 03:20:52 ksekar
-<rdar://problem/3835614> Incorrect LogMsg produces garbage on errors
+Revision 1.440 2007/07/20 16:22:07 mcguire
+<rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
-Revision 1.203 2004/10/08 04:29:25 ksekar
-<rdar://problem/3831842> Allow default search domains to be set via hint from DHCP
+Revision 1.439 2007/07/20 01:14:56 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
+Cleaned up log messages
-Revision 1.202 2004/10/04 05:56:04 cheshire
-<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
+Revision 1.438 2007/07/20 00:54:21 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Revision 1.201 2004/09/30 00:24:59 ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.437 2007/07/19 22:01:27 cheshire
+Added "#pragma mark" sections headings to divide code into related function groups
-Revision 1.200 2004/09/26 23:20:35 ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.436 2007/07/18 03:25:25 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Bring up server-side tunnel on demand, when necessary
-Revision 1.199 2004/09/24 23:54:55 cheshire
-<rdar://problem/3787102> Don't use kCFSocketCloseOnInvalidate
+Revision 1.435 2007/07/18 01:05:08 cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+Add list of client tunnels so we can automatically reconfigure when local address changes
-Revision 1.198 2004/09/24 23:47:49 cheshire
-Correct comment and error message
+Revision 1.434 2007/07/16 20:16:00 vazquez
+<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
+Remove unnecessary LNT init code
-Revision 1.197 2004/09/24 23:39:27 cheshire
-<rdar://problem/3733705> Only IPv6 loopback address advertised on laptop w/no networking
+Revision 1.433 2007/07/14 00:36:07 cheshire
+Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
-Revision 1.196 2004/09/24 20:53:04 cheshire
-Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel"
+Revision 1.432 2007/07/12 23:55:11 cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+Don't need two separate DNSQuestion structures when looking up tunnel endpoint
-Revision 1.195 2004/09/24 19:21:45 cheshire
-<rdar://problem/3671626> Report "Address already in use" errors
+Revision 1.431 2007/07/12 23:34:48 cheshire
+Removed 'LogOperation' message to reduce verbosity in syslog
-Revision 1.194 2004/09/24 19:16:54 cheshire
-Remove "mDNS *const m" parameter from NotifyOfElusiveBug();
-Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)"
+Revision 1.430 2007/07/12 22:16:46 cheshire
+Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
-Revision 1.193 2004/09/22 00:41:59 cheshire
-Move tcp connection status codes into the legal range allocated for mDNS use
+Revision 1.429 2007/07/12 02:51:28 cheshire
+<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Revision 1.192 2004/09/21 21:02:55 cheshire
-Set up ifname before calling mDNS_RegisterInterface()
+Revision 1.428 2007/07/11 23:17:31 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Improve log message to indicate if we're starting or restarting racoon
-Revision 1.191 2004/09/21 19:19:36 cheshire
-<rdar://problem/3760923> Combine WatchForDynDNSChanges() into WatchForNetworkChanges()
+Revision 1.427 2007/07/11 22:50:30 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
-Revision 1.190 2004/09/21 19:04:45 cheshire
-Strip trailing white space from the ends of lines
+Revision 1.426 2007/07/11 20:40:49 cheshire
+<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
+In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
-Revision 1.189 2004/09/21 00:13:28 cheshire
-Fix build failure (io_connect_t and io_object_t are integers, not pointers)
+Revision 1.425 2007/07/11 19:24:19 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
+Configure internal AutoTunnel address
+(For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
+assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
-Revision 1.188 2004/09/20 23:52:02 cheshire
-CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
+Revision 1.424 2007/07/11 19:00:27 cheshire
+Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
-Revision 1.187 2004/09/18 01:37:01 cheshire
-Update comment
+Revision 1.423 2007/07/11 03:00:59 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
-Revision 1.186 2004/09/18 01:11:57 ksekar
-<rdar://problem/3806734> Add a user's default domain to empty-string browse list
+Revision 1.422 2007/07/10 01:21:20 cheshire
+Added (commented out) line for displaying key data for debugging
-Revision 1.185 2004/09/17 01:08:52 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.421 2007/06/25 20:58:11 cheshire
+<rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
+Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
-Revision 1.184 2004/09/17 00:19:10 cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+Revision 1.420 2007/06/22 21:52:14 cheshire
+<rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
-Revision 1.183 2004/09/17 00:15:56 cheshire
-Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
+Revision 1.419 2007/06/22 21:32:00 cheshire
+<rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
-Revision 1.182 2004/09/16 21:36:36 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-Changes to add necessary locking calls around unicast DNS operations
-
-Revision 1.181 2004/09/16 02:03:42 cheshire
-<rdar://problem/3802944> Change address to notify user of kernel flaw
-
-Revision 1.180 2004/09/16 01:58:22 cheshire
-Fix compiler warnings
-
-Revision 1.179 2004/09/16 00:24:49 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.178 2004/09/15 21:51:34 cheshire
-<rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
-Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill
-the machine, so make sure we don't do this until at least three minutes after boot.
-
-Revision 1.177 2004/09/15 01:16:29 cheshire
-<rdar://problem/3387020> mDNSResponder should notify user of kernel flaw
-
-Revision 1.176 2004/09/14 23:42:36 cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
-
-Revision 1.175 2004/09/14 21:35:46 cheshire
-Minor code tidying, and added comments about CFRetainCounts
-
-Revision 1.174 2004/09/14 19:14:57 ksekar
-<rdar://problem/3192531> DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR
-
-Revision 1.173 2004/08/25 23:35:22 ksekar
-<rdar://problem/3770615>: Error converting shared secret from base-64 to binary
-
-Revision 1.172 2004/08/25 02:01:45 cheshire
-<rdar://problem/3774777> Need to be able to get status of Dynamic DNS Host Name Update
-
-Revision 1.171 2004/08/25 01:04:42 cheshire
-Don't need to CFRelease name and array
-
-Revision 1.170 2004/08/25 00:37:28 ksekar
-<rdar://problem/3774635>: Cleanup DynDNS hostname registration code
-
-Revision 1.169 2004/08/18 17:35:41 ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
-
-Revision 1.168 2004/08/17 03:16:24 ksekar
-Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains
-
-Revision 1.167 2004/08/17 00:52:43 ksekar
-Fix config file parse error, make semantics match SCPreferences
-configuration input.
-
-Revision 1.166 2004/08/16 19:55:07 ksekar
-Change enumeration type to BrowseDefault to construct empty-string
-browse list as result of checking 1.161.
-
-Revision 1.165 2004/08/16 19:52:40 ksekar
-Pass computer name + zone for FQDN after keychain notification,
-setting global default service registration domain to the zone.
-
-Revision 1.164 2004/08/16 16:52:37 ksekar
-Pass in zone read from keychain to mDNS_SetFQDNs.
-
-Revision 1.163 2004/08/14 03:22:42 cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
-
-Revision 1.162 2004/08/12 22:34:00 cheshire
-All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII
-
-Revision 1.161 2004/08/11 00:17:46 ksekar
-<rdar://problem/3757662>: 8A227: Need Lighthouse configred machines to
-set default bit for their domains
-
-Revision 1.160 2004/07/29 19:27:16 ksekar
-NAT-PMP Support - minor fixes and cleanup
-
-Revision 1.159 2004/07/26 22:49:31 ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
-
-Revision 1.158 2004/07/13 21:24:24 rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.157 2004/06/08 18:54:48 ksekar
-<rdar://problem/3681378>: mDNSResponder leaks after exploring in Printer Setup Utility
-
-Revision 1.156 2004/06/05 00:04:26 cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
-
-Revision 1.155 2004/06/04 08:58:30 ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
-
-Revision 1.154 2004/05/31 22:22:28 ksekar
-<rdar://problem/3668639>: wide-area domains should be returned in
-reg. domain enumeration
-
-Revision 1.153 2004/05/26 17:06:33 cheshire
-<rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
-
-Revision 1.152 2004/05/18 23:51:26 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.151 2004/05/17 21:46:34 cheshire
-<rdar://problem/3616426>: When interface is turned off, browse "remove" events are delivered with interface index zero
-Take care to correctly update InterfaceIDs when a dormant interface comes back to life
-
-Revision 1.150 2004/05/13 04:54:20 ksekar
-Unified list copy/free code. Added symetric list for
-
-Revision 1.149 2004/05/13 03:55:14 ksekar
-Fixed list traversal bug in FoundDefSearchDomain.
-
-Revision 1.148 2004/05/12 22:03:08 ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms. Changed call to return a copy of the list
-to avoid shared memory issues. Added a routine to free the list.
-
-Revision 1.147 2004/05/12 02:03:25 ksekar
-Non-local domains will only be browsed by default, and show up in
-_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
-
-Revision 1.146 2004/04/27 02:49:15 cheshire
-<rdar://problem/3634655>: mDNSResponder leaks sockets on bind() error
-
-Revision 1.145 2004/04/21 03:08:03 cheshire
-Rename 'alias' to more descriptive name 'primary'
-
-Revision 1.144 2004/04/21 03:04:35 cheshire
-Minor cleanup for clarity
-
-Revision 1.143 2004/04/21 03:03:30 cheshire
-Preparation work: AddInterfaceToList() should return pointer to structure it creates
-
-Revision 1.142 2004/04/21 02:49:11 cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
-
-Revision 1.141 2004/04/21 02:20:47 cheshire
-Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
-
-Revision 1.140 2004/04/14 23:09:29 ksekar
-Support for TSIG signed dynamic updates.
-
-Revision 1.139 2004/04/09 17:40:26 cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
+Revision 1.418 2007/06/21 16:37:43 jgraessley
+Bug #: 5280520
+Reviewed by: Stuart Cheshire
+Additional changes to get this compiling on the embedded platform.
-Revision 1.138 2004/04/09 16:37:16 cheshire
-Suggestion from Bob Bradley:
-Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers
+Revision 1.417 2007/06/20 01:44:00 cheshire
+More information in "Network Configuration Change" message
-Revision 1.137 2004/04/08 00:59:55 cheshire
-<rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
-Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag
+Revision 1.416 2007/06/20 01:10:12 cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-Revision 1.136 2004/04/07 01:08:57 cheshire
-<rdar://problem/3609972> When interface turned off, browse "remove" events delivered with interface index zero
+Revision 1.415 2007/06/15 19:23:38 cheshire
+<rdar://problem/5254053> mDNSResponder renames my host without asking
+Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
-Revision 1.135 2004/03/19 01:01:03 ksekar
-Fixed config file parsing to chop newline
+Revision 1.414 2007/05/17 22:00:59 cheshire
+<rdar://problem/5210966> Lower network change delay from two seconds to one second
-Revision 1.134 2004/03/13 01:57:34 ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
+Revision 1.413 2007/05/16 16:43:27 cheshire
+Only log "bind" failures for our shared mDNS port and for binding to zero
+-- other attempts to bind to a particular port may legitimately fail
-Revision 1.133 2004/02/02 22:46:56 cheshire
-Move "CFRelease(dict);" inside the "if (dict)" check
+Revision 1.412 2007/05/15 21:49:21 cheshire
+Get rid of "#pragma unused"
-Revision 1.132 2004/01/28 02:30:08 ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane. Stopped sending unicast messages on
-every interface. Fixed unicast resolving via mach-port API.
+Revision 1.411 2007/05/14 23:54:55 cheshire
+Instead of sprintf, use safer length-limited mDNS_snprintf
-Revision 1.131 2004/01/27 22:57:48 cheshire
-<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+Revision 1.410 2007/05/12 01:05:00 cheshire
+Updated debugging messages
-Revision 1.130 2004/01/27 22:28:40 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
-Additional lingering port 53 code deleted
+Revision 1.409 2007/05/10 22:39:48 cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
+Only define CountMaskBits for builds with debugging messages
-Revision 1.129 2004/01/27 20:15:23 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.408 2007/05/10 22:19:00 cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
+Don't deliver multicast packets for which we can't find an associated InterfaceID
-Revision 1.128 2004/01/24 23:58:17 cheshire
-Change to use mDNSVal16() instead of shifting and ORing
+Revision 1.407 2007/05/10 21:40:28 cheshire
+Don't log unnecessary "Address already in use" errors when joining multicast groups
-Revision 1.127 2004/01/24 04:59:16 cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.406 2007/05/08 00:56:17 cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
-Revision 1.126 2004/01/23 23:23:15 ksekar
-Added TCP support for truncated unicast messages.
+Revision 1.405 2007/05/04 20:21:39 cheshire
+Improve "connect failed" error message
-Revision 1.125 2004/01/22 03:43:09 cheshire
-Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+Revision 1.404 2007/05/02 19:41:53 cheshire
+No need to alarm people with "Connection reset by peer" syslog message
-Revision 1.124 2004/01/21 21:53:19 cheshire
-<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+Revision 1.403 2007/04/28 01:31:59 cheshire
+Improve debugging support for catching memory corruption problems
-Revision 1.123 2004/01/20 03:18:25 cheshire
-Removed "LogMsg("Hey There!");" that evidently got checked in my mistake
+Revision 1.402 2007/04/26 22:54:57 cheshire
+Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
-Revision 1.122 2003/12/17 20:43:59 cheshire
-<rdar://problem/3496728>: Syslog messages saying "sendto failed"
+Revision 1.401 2007/04/26 00:35:16 cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
-Revision 1.121 2003/12/13 03:05:28 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
+Revision 1.400 2007/04/24 21:50:27 cheshire
+Debugging: Show list of changedKeys in NetworkChanged callback
-Revision 1.120 2003/12/08 21:00:46 rpantos
-Changes to support mDNSResponder on Linux.
+Revision 1.399 2007/04/23 22:28:47 cheshire
+Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
-Revision 1.119 2003/12/03 02:35:15 cheshire
-Also report value of m->timenow when logging sendto() failure
+Revision 1.398 2007/04/23 04:57:00 cheshire
+Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
-Revision 1.118 2003/11/14 20:59:09 cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
+Revision 1.397 2007/04/22 06:02:03 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.117 2003/11/08 22:18:29 cheshire
-<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+Revision 1.396 2007/04/21 21:47:47 cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
-Revision 1.116 2003/09/23 16:39:49 cheshire
-When LogAllOperations is set, also report registration and deregistration of interfaces
+Revision 1.395 2007/04/18 20:58:34 cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
+Needed different code to handle the case where there's only a single search domain
-Revision 1.115 2003/09/10 00:45:55 cheshire
-<rdar://problem/3412328> Don't log "sendto failed" errors during the first two minutes of startup
+Revision 1.394 2007/04/17 23:05:50 cheshire
+<rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
-Revision 1.114 2003/08/27 02:55:13 cheshire
-<rdar://problem/3387910>: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down)
+Revision 1.393 2007/04/17 19:21:29 cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
-Revision 1.113 2003/08/19 22:20:00 cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
+Revision 1.392 2007/04/17 17:15:09 cheshire
+Change NO_CFUSERNOTIFICATION code so it still logs to syslog
-Revision 1.112 2003/08/19 03:04:43 cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
+Revision 1.391 2007/04/07 01:01:48 cheshire
+<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
-Revision 1.111 2003/08/18 22:53:37 cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
+Revision 1.390 2007/04/06 18:45:02 cheshire
+Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
-Revision 1.110 2003/08/16 03:39:00 cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
+Revision 1.389 2007/04/05 21:39:49 cheshire
+Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
-Revision 1.109 2003/08/15 02:19:49 cheshire
-<rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
-Also limit number of messages to at most 100
+Revision 1.388 2007/04/05 21:09:52 cheshire
+Condense sprawling code
-Revision 1.108 2003/08/12 22:24:52 cheshire
-<rdar://problem/3375225> syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35
-This message indicates a kernel bug, but still we don't want to flood syslog.
-Do a sleep(1) after writing this log message, to limit the rate.
+Revision 1.387 2007/04/05 20:40:37 cheshire
+Remove unused mDNSPlatformTCPGetFlags()
-Revision 1.107 2003/08/12 19:56:25 cheshire
-Update to APSL 2.0
+Revision 1.386 2007/04/05 19:50:56 cheshire
+Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
-Revision 1.106 2003/08/12 13:48:32 cheshire
-Add comment explaining clockdivisor calculation
+Revision 1.385 2007/04/03 19:39:19 cheshire
+Fixed intel byte order bug in mDNSPlatformSetDNSServers()
-Revision 1.105 2003/08/12 13:44:14 cheshire
-<rdar://problem/3370229> mDNSResponder *VERY* unhappy if time goes backwards
-Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot)
-instead of gettimeofday() (which can jump back if the user manually changes their time/date)
+Revision 1.384 2007/03/31 01:10:53 cheshire
+Add debugging
-Revision 1.104 2003/08/12 13:12:07 cheshire
-Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static"
+Revision 1.383 2007/03/31 00:13:48 cheshire
+Remove LogMsg
-Revision 1.103 2003/08/08 18:36:04 cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
+Revision 1.382 2007/03/28 21:01:29 cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-Revision 1.102 2003/08/06 00:14:52 cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
-Also add corresponding checks in the IPv6 code path
+Revision 1.381 2007/03/28 15:56:37 cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-Revision 1.101 2003/08/05 22:20:16 cheshire
-<rdar://problem/3330324> Need to check IP TTL on responses
+Revision 1.380 2007/03/26 22:54:46 cheshire
+Fix compile error
-Revision 1.100 2003/08/05 21:18:50 cheshire
-<rdar://problem/3363185> mDNSResponder should ignore 6to4
-Only use interfaces that are marked as multicast-capable (IFF_MULTICAST)
+Revision 1.379 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-Revision 1.99 2003/08/05 20:13:52 cheshire
-<rdar://problem/3294080> mDNSResponder using IPv6 interfaces before they are ready
-Ignore interfaces with the IN6_IFF_NOTREADY flag set
+Revision 1.378 2007/03/22 00:49:20 cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
-Revision 1.98 2003/07/20 03:38:51 ksekar
-<rdar://problem/3320722>
-Completed support for Unix-domain socket based API.
+Revision 1.377 2007/03/21 00:30:05 cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
-Revision 1.97 2003/07/19 03:15:16 cheshire
-Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
-and add the obvious trivial implementations to each platform support layer
+Revision 1.376 2007/03/20 17:07:15 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-Revision 1.96 2003/07/18 00:30:00 cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+Revision 1.375 2007/03/20 00:50:57 cheshire
+<rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
-Revision 1.95 2003/07/12 03:15:20 cheshire
-<rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
-m->hostlabel even if user hasn't actually actually changed their dot-local hostname
+Revision 1.374 2007/03/06 23:29:50 cheshire
+<rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
-Revision 1.94 2003/07/03 00:51:54 cheshire
-<rdar://problem/3287213> When select() and recvmgs() disagree, get more info from kernel about the socket state
+Revision 1.373 2007/02/28 01:51:20 cheshire
+Added comment about reverse-order IP address
-Revision 1.93 2003/07/03 00:09:14 cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
-Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name);
+Revision 1.372 2007/02/28 01:06:48 cheshire
+Use %#a format code instead of %d.%d.%d.%d
-Revision 1.92 2003/07/02 21:19:51 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+Revision 1.371 2007/02/08 21:12:28 cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-Revision 1.91 2003/06/24 01:53:51 cheshire
-Minor update to comments
+Revision 1.370 2007/01/16 22:59:58 cheshire
+Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
-Revision 1.90 2003/06/24 01:51:47 cheshire
-<rdar://problem/3303118> Oops: Double-dispose of sockets
-Don't need to close sockets: CFSocketInvalidate() does that for us
+Revision 1.369 2007/01/10 02:09:32 cheshire
+Better LogOperation record of keys read from System Keychain
-Revision 1.89 2003/06/21 18:12:47 cheshire
-<rdar://problem/3296061> mDNSResponder cannot handle interfaces whose total name is >3 chars
-One-line change: should say "IF_NAMESIZE", not sizeof(ifname)
+Revision 1.368 2007/01/10 01:25:31 cheshire
+Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
-Revision 1.88 2003/06/12 23:38:37 cheshire
-<rdar://problem/3291162> mDNSResponder doesn't detect some configuration changes
-Also check that scope_id matches before concluding that two interfaces are the same
+Revision 1.367 2007/01/10 01:22:01 cheshire
+Make sure c1, c2, c3 are initialized
-Revision 1.87 2003/06/10 01:14:11 cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
+Revision 1.366 2007/01/09 22:37:20 cheshire
+Provide ten-second grace period for deleted keys, to give mDNSResponder
+time to delete host name before it gives up access to the required key.
-Revision 1.86 2003/05/28 02:41:52 cheshire
-<rdar://problem/3034346> Time to remove Mac OS 9 UDP Port 53 legacy support
+Revision 1.365 2007/01/09 21:09:20 cheshire
+Need locking in KeychainChanged()
-Revision 1.85 2003/05/28 02:39:47 cheshire
-Minor change to debugging messages
+Revision 1.364 2007/01/09 20:17:04 cheshire
+mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
-Revision 1.84 2003/05/27 22:29:40 cheshire
-Remove out-dated comment
+Revision 1.363 2007/01/09 02:41:18 cheshire
+uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
+moved it to mDNS_Init() in mDNS.c (core code)
-Revision 1.83 2003/05/26 03:21:29 cheshire
-Tidy up address structure naming:
-mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
+Revision 1.362 2007/01/08 23:54:01 cheshire
+Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
-Revision 1.82 2003/05/26 03:01:27 cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
+Revision 1.361 2007/01/05 08:30:48 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.81 2003/05/24 02:06:42 cheshire
-<rdar://problem/3268480> IPv6 Multicast Loopback doesn't work
-Tried setting IPV6_MULTICAST_LOOP; it doesn't help.
-However, it is probably wise to have the code explicitly set this socket
-option anyway, in case the default changes in later versions of Unix.
+Revision 1.360 2007/01/04 00:12:24 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.80 2003/05/24 02:02:24 cheshire
-<rdar://problem/3221880> if_indextoname consumes a lot of CPU
-Fix error in myIfIndexToName; was returning prematurely
+Revision 1.359 2006/12/22 21:14:37 cheshire
+Added comment explaining why we allow both "ddns" and "sndd" as valid item types
+The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
-Revision 1.79 2003/05/23 23:07:44 cheshire
-<rdar://problem/3268199> Must not write to stderr when running as daemon
+Revision 1.358 2006/12/22 20:59:50 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.78 2003/05/23 01:19:04 cheshire
-<rdar://problem/3267085> mDNSResponder needs to signal type of service to AirPort
-Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
+Revision 1.357 2006/12/21 00:09:45 cheshire
+Use mDNSPlatformMemZero instead of bzero
-Revision 1.77 2003/05/23 01:12:05 cheshire
-Minor code tidying
+Revision 1.356 2006/12/20 23:15:53 mkrochma
+Fix the private domain list code so that it actually works
-Revision 1.76 2003/05/22 01:26:01 cheshire
-Tidy up log messages
+Revision 1.355 2006/12/20 23:04:36 mkrochma
+Fix crash when adding private domain list to Dynamic Store
-Revision 1.75 2003/05/22 00:07:09 cheshire
-<rdar://problem/3264366> myCFSocketCallBack recvfrom(5) error 1, errno 35
-Extra logging to determine whether there is a bug in CFSocket
+Revision 1.354 2006/12/19 22:43:55 cheshire
+Fix compiler warnings
-Revision 1.74 2003/05/21 20:20:12 cheshire
-Fix warnings (mainly printf format string warnings, like using "%d" where
-it should say "%lu", etc.) and improve error logging (use strerror()
-to include textual error message as well as numeric error in log messages).
+Revision 1.353 2006/12/14 22:08:29 cheshire
+Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
+to release data allocated by SecKeychainItemCopyAttributesAndData()
-Revision 1.73 2003/05/21 17:56:29 ksekar
-<rdar://problem/3191277>: mDNSResponder doesn't watch for IPv6 address changes
+Revision 1.352 2006/12/14 02:33:26 cheshire
+<rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
-Revision 1.72 2003/05/14 18:48:41 cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-More minor refinements:
-mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory
-mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away
+Revision 1.351 2006/11/28 21:37:51 mkrochma
+Tweak where the private DNS data is written
-Revision 1.71 2003/05/14 07:08:37 cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
+Revision 1.350 2006/11/28 07:55:02 herscher
+<rdar://problem/4742743> dnsextd has a slow memory leak
-Revision 1.70 2003/05/07 18:30:24 cheshire
-Fix signed/unsigned comparison warning
+Revision 1.349 2006/11/28 07:45:58 herscher
+<rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
-Revision 1.69 2003/05/06 20:14:44 cheshire
-Change "tp" to "tv"
+Revision 1.348 2006/11/16 21:47:20 mkrochma
+<rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
-Revision 1.68 2003/05/06 00:00:49 cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
+Revision 1.347 2006/11/10 00:54:16 cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
-Revision 1.67 2003/04/29 00:43:44 cheshire
-Fix compiler warnings
+Revision 1.346 2006/10/31 02:34:58 cheshire
+<rdar://problem/4692130> Stop creating HINFO records
-Revision 1.66 2003/04/26 02:41:58 cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
+Revision 1.345 2006/09/21 20:04:38 mkrochma
+Accidently changed function name while checking in previous fix
-Revision 1.65 2003/04/26 02:34:01 cheshire
-Add missing mDNSexport
+Revision 1.344 2006/09/21 19:04:13 mkrochma
+<rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
-Revision 1.64 2003/04/15 16:48:06 jgraessl
-<rdar://problem/3228833>
-Modified code in CFSocket notifier function to read all packets on the socket
-instead of reading only one packet every time the notifier was called.
+Revision 1.343 2006/09/15 21:20:16 cheshire
+Remove uDNS_info substructure from mDNS_struct
-Revision 1.63 2003/04/15 16:33:50 jgraessl
-<rdar://problem/3221880>
-Switched to our own copy of if_indextoname to improve performance.
+Revision 1.342 2006/08/16 00:31:50 mkrochma
+<rdar://problem/4386944> Get rid of NotAnInteger references
-Revision 1.62 2003/03/28 01:55:44 cheshire
-Minor improvements to debugging messages
+Revision 1.341 2006/08/14 23:24:40 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.61 2003/03/27 03:30:56 cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
- (it never really needed to deregister the interface at all)
+Revision 1.340 2006/07/29 19:11:13 mkrochma
+Change GetUserSpecifiedDDNSConfig LogMsg to debugf
-Revision 1.60 2003/03/15 04:40:38 cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
+Revision 1.339 2006/07/27 03:24:35 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinement: Declare KQueueEntry parameter "const"
-Revision 1.59 2003/03/11 01:23:26 cheshire
-<rdar://problem/3194246> mDNSResponder socket problems
+Revision 1.338 2006/07/27 02:59:25 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
+after releasing BigMutex, in case actions it took have resulted in new work for the
+kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
+add new active interfaces to its list, and consequently schedule queries to be sent).
-Revision 1.58 2003/03/06 01:43:04 cheshire
-<rdar://problem/3189097> Additional debugging code in mDNSResponder
-Improve "LIST_ALL_INTERFACES" output
+Revision 1.337 2006/07/22 06:11:37 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Revision 1.57 2003/03/05 22:36:27 cheshire
-<rdar://problem/3186338> Loopback doesn't work with mDNSResponder-27
-Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use
+Revision 1.336 2006/07/15 02:01:32 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
-Revision 1.56 2003/03/05 01:50:38 cheshire
-<rdar://problem/3189097> Additional debugging code in mDNSResponder
+Revision 1.335 2006/07/14 05:25:11 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
-Revision 1.55 2003/02/21 01:54:09 cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
+Revision 1.334 2006/07/05 23:42:00 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Revision 1.54 2003/02/20 06:48:35 cheshire
-<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
+Revision 1.333 2006/06/29 05:33:30 cheshire
+<rdar://problem/4607043> mDNSResponder conditional compilation options
-Revision 1.53 2003/01/29 02:21:23 cheshire
-Return mStatus_Invalid if can't send packet because socket not available
+Revision 1.332 2006/06/28 09:10:36 cheshire
+Extra debugging messages
-Revision 1.52 2003/01/28 19:39:43 jgraessl
-Enabling AAAA over IPv4 support.
+Revision 1.331 2006/06/21 22:29:42 cheshire
+Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
-Revision 1.51 2003/01/28 05:11:23 cheshire
-Fixed backwards comparison in SearchForInterfaceByName
+Revision 1.330 2006/06/20 23:06:00 cheshire
+Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
-Revision 1.50 2003/01/13 23:49:44 jgraessl
-Merged changes for the following fixes in to top of tree:
-<rdar://problem/3086540> computer name changes not handled properly
-<rdar://problem/3124348> service name changes are not properly handled
-<rdar://problem/3124352> announcements sent in pairs, failing chattiness test
+Revision 1.329 2006/06/08 23:22:33 cheshire
+Comment changes
-Revision 1.49 2002/12/23 22:13:30 jgraessl
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
+Revision 1.328 2006/03/19 03:27:49 cheshire
+<rdar://problem/4118624> Suppress "interface flapping" logic for loopback
-Revision 1.48 2002/11/22 01:37:52 cheshire
-<rdar://problem/3108426> mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities
+Revision 1.327 2006/03/19 02:00:09 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-Revision 1.47 2002/09/21 20:44:51 zarzycki
-Added APSL info
+Revision 1.326 2006/03/08 22:42:23 cheshire
+Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
-Revision 1.46 2002/09/19 21:25:35 cheshire
-mDNS_snprintf() doesn't need to be in a separate file
+Revision 1.325 2006/01/10 00:39:17 cheshire
+Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
-Revision 1.45 2002/09/17 01:45:13 cheshire
-Add LIST_ALL_INTERFACES symbol for debugging
+Revision 1.324 2006/01/09 19:28:59 cheshire
+<rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
-Revision 1.44 2002/09/17 01:36:23 cheshire
-Move Puma support to mDNSMacOSXPuma.c
+Revision 1.323 2006/01/05 21:45:27 cheshire
+<rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
-Revision 1.43 2002/09/17 01:05:28 cheshire
-Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global
+Revision 1.322 2006/01/05 21:41:50 cheshire
+<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
-Revision 1.42 2002/09/16 23:13:50 cheshire
-Minor code tidying
+Revision 1.321 2006/01/05 21:35:06 cheshire
+Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
- */
+*/
// ***************************************************************************
// mDNSMacOSX.c:
// including ones that mDNSResponder chooses not to use.
#define LIST_ALL_INTERFACES 0
-// For debugging, being able to identify software versions is useful.
-// Some people are concerned that this information could be exploited by hackers.
-// I'm not totally convinced by that argument, but we don't want to cause our users distress,
-// so for shipping code, define "NO_HINFO" to suppress the generation of HINFO records. -- SC
-#define NO_HINFO 1
-
// For enabling AAAA records over IPv4. Setting this to 0 sends only
// A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
// AAAA and A records over both IPv4 and IPv6.
#define AAAA_OVER_V4 1
+// In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable
+// IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
+// which means there's a good chance that most or all the other devices on that network should also have IPv4.
+// By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half.
+// At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
+// so were willing to make that sacrifice.
+// In Mac OS X 10.5, in 2007, two things have changed:
+// 1. IPv6-only devices are starting to become more common, so we can't ignore them.
+// 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
+
+#define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
+
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "DNSCommon.h"
+#include "uDNS.h"
#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
#include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon
#include "PlatformCommon.h"
+
#include <stdio.h>
#include <stdarg.h> // For va_list support
#include <net/if.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
+#include <sys/event.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <time.h> // platform support for UTC time
#include <arpa/inet.h> // for inet_aton
+#include <pthread.h>
#include <netinet/in.h> // For IP_RECVTTL
#ifndef IP_RECVTTL
#include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
#include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
#include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
+#include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#endif
+
+#ifndef NO_SECURITYFRAMEWORK
+#include <Security/SecureTransport.h>
#include <Security/Security.h>
+#endif /* NO_SECURITYFRAMEWORK */
+#include <DebugServices.h>
#include "dnsinfo.h"
// Code contributed by Dave Heller:
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
+#include <mach/mach_error.h>
+#include <mach/mach_port.h>
#include <mach/mach_time.h>
+#include "helper.h"
-typedef struct SearchListElem
- {
- struct SearchListElem *next;
- domainname domain;
- int flag;
- DNSQuestion BrowseQ;
- DNSQuestion DefBrowseQ;
- DNSQuestion LegacyBrowseQ;
- DNSQuestion RegisterQ;
- DNSQuestion DefRegisterQ;
- ARListElem *AuthRecs;
- } SearchListElem;
-
+#define kInterfaceSpecificOption "interface="
// ***************************************************************************
// Globals
-static mDNSu32 clockdivisor = 0;
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Globals
+#endif
-// for domain enumeration and default browsing/registration
-static SearchListElem *SearchList = NULL; // where we search for _browse domains
-static DNSQuestion LegacyBrowseDomainQ; // our local enumeration query for _legacy._browse domains
-static DNameListElem *DefBrowseList = NULL; // cache of answers to above query (where we search for empty string browses)
-static DNameListElem *DefRegList = NULL; // manually generated list of domains where we register for empty string registrations
-static ARListElem *SCPrefBrowseDomains = NULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
+static mDNSu32 clockdivisor = 0;
-static domainname DynDNSRegDomain; // Default wide-area zone for service registration
-static CFArrayRef DynDNSBrowseDomains = NULL; // Default wide-area zones for legacy ("empty string") browses
-static domainname DynDNSHostname;
+mDNSexport int KQueueFD;
-static mDNSBool DomainDiscoveryDisabled = mDNSfalse;
+#ifndef NO_SECURITYFRAMEWORK
+static CFArrayRef ServerCerts;
+#endif /* NO_SECURITYFRAMEWORK */
-#define CONFIG_FILE "/etc/mDNSResponder.conf"
#define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
-#define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
-// Function Prototypes
-mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add);
+CFStringRef NetworkChangedKey_IPv4;
+CFStringRef NetworkChangedKey_IPv6;
+CFStringRef NetworkChangedKey_Hostnames;
+CFStringRef NetworkChangedKey_Computername;
+CFStringRef NetworkChangedKey_DNS;
+CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
+CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
// ***************************************************************************
// Functions
-// routines to allow access to default domain lists from daemon layer
-
-mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
- {
- return mDNS_CopyDNameList(DefBrowseList);
- }
-
-mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
- {
- return mDNS_CopyDNameList(DefRegList);
- }
-
-// utility routines to manage registration domain lists
-
-mDNSlocal void AddDefRegDomain(domainname *d)
- {
- DNameListElem *newelem = NULL, *ptr;
-
- // make sure name not already in list
- for (ptr = DefRegList; ptr; ptr = ptr->next)
- {
- if (SameDomainName(&ptr->name, d))
- { debugf("duplicate addition of default reg domain %##s", d->c); return; }
- }
-
- newelem = mallocL("DNameListElem", sizeof(*newelem));
- if (!newelem) { LogMsg("Error - malloc"); return; }
- AssignDomainName(&newelem->name, d);
- newelem->next = DefRegList;
- DefRegList = newelem;
-
- DefaultRegDomainChanged(d, mDNStrue);
- udsserver_default_reg_domain_changed(d, mDNStrue);
- }
-
-mDNSlocal void RemoveDefRegDomain(domainname *d)
- {
- DNameListElem *ptr = DefRegList, *prev = NULL;
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Utility Functions
+#endif
- while (ptr)
- {
- if (SameDomainName(&ptr->name, d))
- {
- if (prev) prev->next = ptr->next;
- else DefRegList = ptr->next;
- freeL("DNameListElem", ptr);
- DefaultRegDomainChanged(d, mDNSfalse);
- udsserver_default_reg_domain_changed(d, mDNSfalse);
- return;
- }
- prev = ptr;
- ptr = ptr->next;
- }
- debugf("Requested removal of default registration domain %##s not in contained in list", d->c);
- }
+// We only attempt to send and receive multicast packets on interfaces that are
+// (a) flagged as multicast-capable
+// (b) *not* flagged as point-to-point (e.g. modem)
+// Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
+// to run up the user's bill sending multicast traffic over a link where there's only a single device at the
+// other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
+#define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT))
-mDNSexport void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg)
+mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
{
static int notifyCount = 0;
if (notifyCount) return;
-
+
// If we display our alert early in the boot process, then it vanishes once the desktop appears.
// To avoid this, we don't try to display alerts in the first three minutes after boot.
if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
-
+
// Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
#if !ForceAlerts
{
}
#endif
- // Send a notification to the user to contact coreos-networking
+ LogMsg("%s", title);
+ LogMsg("%s", msg);
+ // Display a notification to the user
notifyCount++;
- CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
- CFStringRef alertFormat = CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of <rdar://problem/%d>. %s");
- CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, alertFormat, radarid, msg);
+
+#ifndef NO_CFUSERNOTIFICATION
+ static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
+ CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
+ CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
+ CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
+ CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
+#endif /* NO_CFUSERNOTIFICATION */
}
-mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh)
+mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
{
static struct ifaddrs *ifa = NULL;
-
+
if (refresh && ifa)
{
freeifaddrs(ifa);
ifa = NULL;
}
-
+
if (ifa == NULL) getifaddrs(&ifa);
-
+
return ifa;
}
if (i->Exists && !strcmp(i->ifa_name, ifname) &&
((AAAA_OVER_V4 ) ||
(type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
- (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i);
+ (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
return(NULL);
}
-mDNSlocal int myIfIndexToName(u_short index, char* name)
+mDNSlocal int myIfIndexToName(u_short index, char *name)
{
struct ifaddrs *ifa;
for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
if (ifa->ifa_addr->sa_family == AF_LINK)
if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index)
- { strncpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
+ { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
return -1;
}
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
{
NetworkInterfaceInfoOSX *i;
if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
- if (index)
- for (i = m->p->InterfaceList; i; i = i->next)
- // Don't get tricked by inactive interfaces with no InterfaceID set
- if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
+ if (index == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
+
+ // Don't get tricked by inactive interfaces with no InterfaceID set
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
+
+ // Not found. Make sure our interface list is up to date, then try again.
+ LogOperation("InterfaceID for interface index %d not found; Updating interface list", index);
+ mDNSMacOSXNetworkChanged(m);
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID);
+
return(mDNSNULL);
}
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
{
NetworkInterfaceInfoOSX *i;
if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
- if (id)
- for (i = m->p->InterfaceList; i; i = i->next)
- // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
- if ((mDNSInterfaceID)i == id) return(i->scope_id);
- return 0;
+ if (id == mDNSInterface_Any ) return(0);
+
+ // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if ((mDNSInterfaceID)i == id) return(i->scope_id);
+
+ // Not found. Make sure our interface list is up to date, then try again.
+ LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id);
+ mDNSMacOSXNetworkChanged(m);
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if ((mDNSInterfaceID)i == id) return(i->scope_id);
+
+ return(0);
}
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - UDP & TCP send & receive
+#endif
+
mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
{
mDNSBool result = mDNSfalse;
SCNetworkConnectionFlags flags;
SCNetworkReachabilityRef ReachRef = NULL;
- ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
+ ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);
if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
result = flags & kSCNetworkFlagsConnectionRequired;
end:
if (ReachRef) CFRelease(ReachRef);
- return result;
+ return result;
}
// NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort)
{
- #pragma unused(m)
-
// Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers
// to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code
// doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers.
char *ifa_name = info ? info->ifa_name : "unicast";
struct sockaddr_storage to;
int s = -1, err;
+ mStatus result = mStatus_NoError;
// Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our
// anonymous socket created for this purpose, so that we'll receive the response.
// If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably.
- if (info && !mDNSAddrIsDNSMulticast(dst))
+ if (InterfaceID && !mDNSAddrIsDNSMulticast(dst))
{
const DNSMessage *const m = (DNSMessage *)msg;
if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
}
-
+
if (dst->type == mDNSAddrType_IPv4)
{
struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
sin_to->sin_family = AF_INET;
sin_to->sin_port = dstPort.NotAnInteger;
sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
- s = info ? info->ss.sktv4 : m->p->unicastsockets.sktv4;
+ s = m->p->permanentsockets.sktv4;
+ if (info) // Specify outgoing interface
+ {
+ if (!mDNSAddrIsDNSMulticast(dst))
+ {
+ #ifdef IP_FORCE_OUT_IFP
+ setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, ifa_name, strlen(ifa_name) + 1);
+ #else
+ {
+ static int displayed = 0;
+ if (!displayed)
+ {
+ displayed = 1;
+ LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets");
+ }
+ }
+ #endif
+ }
+ else
+ {
+ err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
+ if (err < 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+ }
+ }
}
else if (dst->type == mDNSAddrType_IPv6)
{
sin6_to->sin6_flowinfo = 0;
sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
sin6_to->sin6_scope_id = info ? info->scope_id : 0;
- s = info ? info->ss.sktv6 : m->p->unicastsockets.sktv6;
+ s = m->p->permanentsockets.sktv6;
+ if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
+ {
+ err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
+ if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno));
+ }
}
else
{
return mStatus_BadParamErr;
}
- // Don't send if it would cause dial on demand connection initiation. As an optimization,
- // don't bother consulting reachability API / routing table when sending Multicast DNS
- // since we ignore PPP interfaces for mDNS traffic
- if (!mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
+ // Don't send if it would cause dial-on-demand connection initiation.
+ // As an optimization, don't bother consulting reachability API / routing
+ // table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic.
+ if (!info && !mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
{
debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
return mStatus_NoError;
}
-
+
if (s >= 0)
verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
if (err < 0)
{
- // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+ static int MessageCount = 0;
+ // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
if (!mDNSAddressIsAllDNSLinkGroup(dst))
if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
// Don't report EHOSTUNREACH in the first three minutes after boot
if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
// Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
- LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
- InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
- return(mStatus_UnknownErr);
+ if (MessageCount < 1000)
+ {
+ MessageCount++;
+ LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
+ InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+ }
+ result = mStatus_UnknownErr;
}
-
- return(mStatus_NoError);
+
+#ifdef IP_FORCE_OUT_IFP
+ if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
+ setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, "", 1);
+#endif
+
+ return(result);
}
mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
msg.msg_control = (caddr_t)&ancillary;
msg.msg_controllen = sizeof(ancillary);
msg.msg_flags = 0;
-
+
// Receive the data
n = recvmsg(s, &msg, 0);
if (n<0)
}
if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
{
- if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
- s, msg.msg_controllen, sizeof(struct cmsghdr));
+ if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
+ s, n, msg.msg_controllen, sizeof(struct cmsghdr));
return(-1);
}
if (msg.msg_flags & MSG_CTRUNC)
if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
return(-1);
}
-
+
*fromlen = msg.msg_namelen;
-
+
// Parse each option out of the ancillary data.
for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
{
if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
{
dstaddr->type = mDNSAddrType_IPv4;
- dstaddr->ip.v4.NotAnInteger = *(u_int32_t*)CMSG_DATA(cmPtr);
+ dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
}
if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
if (sdl->sdl_nlen < IF_NAMESIZE)
{
- mDNSPlatformMemCopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
+ mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
ifname[sdl->sdl_nlen] = 0;
// debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
}
}
if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
- {
*ttl = *(u_char*)CMSG_DATA(cmPtr);
- }
if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
{
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
}
if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
- {
*ttl = *(int*)CMSG_DATA(cmPtr);
- }
}
return(n);
}
-// On entry, context points to our CFSocketSet
-// If ss->info is NULL, we received this packet on our anonymous unicast socket
-// If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface
-mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
+mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
{
- const CFSocketSet *const ss = (const CFSocketSet *)context;
+ const KQSocketSet *const ss = (const KQSocketSet *)context;
mDNS *const m = ss->m;
- const int skt = CFSocketGetNative(cfs);
- const int s1 = (cfs == ss->cfsv4) ? ss->sktv4 : (cfs == ss->cfsv6) ? ss->sktv6 : -1;
int err, count = 0;
-
- (void)address; // Parameter not used
- (void)data; // Parameter not used
-
- if (CallBackType != kCFSocketReadCallBack)
- LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType);
- if (s1 < 0 || s1 != skt)
+ if (filter != EVFILT_READ)
+ LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
+
+ if (s1 != ss->sktv4 && s1 != ss->sktv6)
{
- LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs);
- LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss->cfsv4, ss->sktv4);
- LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss->cfsv6, ss->sktv6);
- }
+ LogMsg("myKQSocketCallBack: native socket %d", s1);
+ LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4);
+ LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
+ }
while (1)
{
- // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
- mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL;
mDNSAddr senderAddr, destAddr;
mDNSIPPort senderPort, destPort = MulticastDNSPort;
struct sockaddr_storage from;
mDNSu8 ttl;
err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
if (err < 0) break;
-
+
count++;
if (from.ss_family == AF_INET)
{
senderAddr.type = mDNSAddrType_IPv4;
senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr;
senderPort.NotAnInteger = sin->sin_port;
+ //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
}
else if (from.ss_family == AF_INET6)
{
senderAddr.type = mDNSAddrType_IPv6;
senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
senderPort.NotAnInteger = sin6->sin6_port;
+ //LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
}
else
{
- LogMsg("myCFSocketCallBack from is unknown address family %d", from.ss_family);
+ LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
return;
}
- if (mDNSAddrIsDNSMulticast(&destAddr))
- {
- // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the
- // sockets API means that even though this socket has only officially joined the multicast group
- // on one specific interface, the kernel will still deliver multicast packets to it no matter which
- // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
- // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
- // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
- if (!ss->info || !ss->info->Exists)
- {
- verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr, &destAddr);
- return;
- }
- else if (strcmp(ss->info->ifa_name, packetifname))
- {
- verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)",
- &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name, packetifname);
- return;
- }
- else
- verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s",
- &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
- }
- else
- {
- // Note: Unicast packets are delivered to *one* of our listening sockets,
- // not necessarily the one bound to the physical interface where the packet arrived.
- // To sort this out we search our interface list and update InterfaceID to reference
- // the mDNSCore interface object for the interface where the packet was actually received.
- NetworkInterfaceInfo *intf = m->HostInterfaces;
- while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
- if (intf) InterfaceID = intf->InterfaceID;
- }
+ // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
+ mDNSInterfaceID InterfaceID = mDNSNULL;
+ NetworkInterfaceInfo *intf = m->HostInterfaces;
+ while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
+ // When going to sleep we deregister all our interfaces, but if the machine
+ // takes a few seconds to sleep we may continue to receive multicasts
+ // during that time, which would confuse mDNSCoreReceive, because as far
+ // as it's concerned, we should have no active interfaces any more.
+ // Hence we ignore multicasts for which we can find no matching InterfaceID.
+ if (intf) InterfaceID = intf->InterfaceID;
+ else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
+
+// LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
+// &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name);
mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID);
}
if (err < 0 && (errno != EWOULDBLOCK || count == 0))
{
// Something is busted here.
- // CFSocket says there is a packet, but myrecvfrom says there is not.
+ // kqueue says there is a packet, but myrecvfrom says there is not.
// Try calling select() to get another opinion.
// Find out about other socket parameter that can help understand why select() says the socket is ready for read
// All of this is racy, as data may have arrived after the call to select()
+ static unsigned int numLogMessages = 0;
int save_errno = errno;
int so_error = -1;
int so_nread = -1;
int fionread = -1;
socklen_t solen = sizeof(int);
fd_set readfds;
+ struct timeval timeout;
+ int selectresult;
FD_ZERO(&readfds);
FD_SET(s1, &readfds);
- struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
- int selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
+ selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
- LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno);
+ LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
- LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno);
+ LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
if (ioctl(s1, FIONREAD, &fionread) == -1)
- LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno);
- static unsigned int numLogMessages = 0;
+ LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
if (numLogMessages++ < 100)
- LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
+ LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
if (numLogMessages > 5)
- NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328,
- "Alternatively, you can send email to radar-3387020@group.apple.com. "
+ NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
+ "Congratulations, you've reproduced an elusive bug.\r"
+ "Please contact the current assignee of <rdar://problem/3375328>.\r"
+ "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
sleep(1); // After logging this error, rate limit so we don't flood syslog
}
}
-// TCP socket support for unicast DNS and Dynamic DNS Update
+// TCP socket support
-typedef struct
+struct TCPSocket_struct
{
- TCPConnectionCallback callback;
- void *context;
- int connected;
- } tcpInfo_t;
+ TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
+ TCPConnectionCallback callback;
+ int fd;
+ KQueueEntry kqEntry;
+#ifndef NO_SECURITYFRAMEWORK
+ SSLContextRef tlsContext;
+#endif /* NO_SECURITYFRAMEWORK */
+ void *context;
+ mDNSBool setup;
+ mDNSBool handshakecomplete;
+ mDNSBool connected;
+ };
+
+#ifndef NO_SECURITYFRAMEWORK
-mDNSlocal void tcpCFSocketCallback(CFSocketRef cfs, CFSocketCallBackType CallbackType, CFDataRef address,
- const void *data, void *context)
+mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
{
- #pragma unused(CallbackType, address, data)
- mDNSBool connect = mDNSfalse;
-
- tcpInfo_t *info = context;
- if (!info->connected)
- {
- connect = mDNStrue;
- info->connected = mDNStrue; // prevent connected flag from being set in future callbacks
- }
- info->callback(CFSocketGetNative(cfs), info->context, connect);
- // NOTE: the callback may call CloseConnection here, which frees the context structure!
+ int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
+ if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
+ if (ret >= 0) { *dataLength = ret; return(noErr); }
+ *dataLength = 0;
+ if (errno == EAGAIN ) return(errSSLWouldBlock);
+ if (errno == ENOENT ) return(errSSLClosedGraceful);
+ if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
+ LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno, strerror(errno));
+ return(errSSLClosedAbort);
}
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context, int *descriptor)
+mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
{
- int sd, on = 1; // "on" for setsockopt
- struct sockaddr_in saddr;
- CFSocketContext cfContext = { 0, NULL, 0, 0, 0 };
- tcpInfo_t *info;
- CFSocketRef sr;
- CFRunLoopSourceRef rls;
-
- (void)InterfaceID; //!!!KRS use this if non-zero!!!
+ int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
+ if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
+ if (ret > 0) { *dataLength = ret; return(noErr); }
+ *dataLength = 0;
+ if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
+ if ( errno == EAGAIN ) return(errSSLWouldBlock);
+ if ( errno == ECONNRESET) return(errSSLClosedAbort);
+ LogMsg("ERROR: tlsSockRead: error %d %s\n", errno, strerror(errno));
+ return(errSSLClosedAbort);
+ }
- *descriptor = 0;
- if (dst->type != mDNSAddrType_IPv4)
- {
- LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
- return mStatus_UnknownErr;
- }
+mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
+ {
+ mStatus err = SSLNewContext(server, &sock->tlsContext);
+ if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
- bzero(&saddr, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_port = dstport.NotAnInteger;
- saddr.sin_len = sizeof(saddr);
- memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
+ err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
+ if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); }
- // Don't send if it would cause dial on demand connection initiation.
- if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
- {
- debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
- return mStatus_UnknownErr;
- }
+ err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
+ if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
- sd = socket(AF_INET, SOCK_STREAM, 0);
- if (sd < 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd, errno, strerror(errno)); return mStatus_UnknownErr; }
+ return(err);
+ }
- // set non-blocking
- if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
- {
- LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
- return mStatus_UnknownErr;
- }
-
- // receive interface identifiers
- if (setsockopt(sd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
- {
- LogMsg("setsockopt IP_RECVIF - %s", strerror(errno));
- return mStatus_UnknownErr;
- }
- // set up CF wrapper, add to Run Loop
- info = mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t));
- info->callback = callback;
- info->context = context;
- cfContext.info = info;
- sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack | kCFSocketConnectCallBack,
- tcpCFSocketCallback, &cfContext);
- if (!sr)
- {
- LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed");
- freeL("mDNSPlatformTCPConnect", info);
- return mStatus_UnknownErr;
- }
+mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
+ {
+ static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
+ const domainname *d1 = mDNSNULL; // TLD
+ const domainname *d2 = mDNSNULL; // SLD
+ const domainname *d3 = mDNSNULL;
+ while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); }
+ return(d3 && SameDomainName(d3, mmc));
+ }
- rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0);
- if (!rls)
- {
- LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed");
- freeL("mDNSPlatformTCPConnect", info);
- return mStatus_UnknownErr;
- }
-
- CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
- CFRelease(rls);
-
- // initiate connection wth peer
- if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+#endif /* NO_SECURITYFRAMEWORK */
+
+mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
+ {
+ TCPSocket *sock = context;
+ mStatus err = mStatus_NoError;
+
+ //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
+ //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
+ // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
+ if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
+
+ if (sock->flags & kTCPSocketFlags_UseTLS)
{
- if (errno == EINPROGRESS)
+#ifndef NO_SECURITYFRAMEWORK
+ if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
+ if (!sock->handshakecomplete)
{
- info->connected = 0;
- *descriptor= sd;
- return mStatus_ConnPending;
+ //LogMsg("tcpKQSocketCallback Starting SSLHandshake");
+ err = SSLHandshake(sock->tlsContext);
+ //if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete");
+ if (!err) sock->handshakecomplete = mDNStrue;
+ else if (err == errSSLWouldBlock) return;
+ else { LogMsg("KQ SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; }
}
- LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno));
- freeL("mDNSPlatformTCPConnect", info);
- CFSocketInvalidate(sr); // Note: Also closes the underlying socket
- return mStatus_ConnFailed;
+#else
+ err = mStatus_UnsupportedErr;
+#endif /* NO_SECURITYFRAMEWORK */
}
- info->connected = 1;
- *descriptor = sd;
- return mStatus_ConnEstablished;
+
+ mDNSBool connect = !sock->connected;
+ sock->connected = mDNStrue;
+ sock->callback(sock, sock->context, connect, err);
+ // NOTE: the callback may call CloseConnection here, which frees the context structure!
}
-mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
+mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
{
- CFSocketContext cfContext;
- tcpInfo_t *info;
- CFSocketRef sr;
+ struct kevent new_event;
+ EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
+ return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
+ }
- if (sd < 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd);
+mDNSexport void KQueueLock(mDNS *const m)
+ {
+ pthread_mutex_lock(&m->p->BigMutex);
+ m->p->BigMutexStartTime = mDNSPlatformRawTime();
+ }
- // Get the CFSocket for the descriptor
- sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketNoCallBack, NULL, NULL);
- if (!sr) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; }
+mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
+ {
+ mDNSs32 end = mDNSPlatformRawTime();
+ (void)task;
+ if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
+ LogOperation("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
- CFSocketGetContext(sr, &cfContext);
- if (!cfContext.info)
- {
- LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context");
- CFRelease(sr);
- return;
- }
- CFRelease(sr); // this only releases the copy we allocated with CreateWithNative above
-
- info = cfContext.info;
+ pthread_mutex_unlock(&m->p->BigMutex);
- // Note: MUST NOT close the underlying native BSD socket.
- // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
- // because it first has to unhook the sockets from its select() call, before it can safely close them.
- CFSocketInvalidate(sr);
- CFRelease(sr);
- freeL("mDNSPlatformTCPCloseConnection", info);
+ char wake = 1;
+ if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
+ LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno, strerror(errno));
}
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
{
- int nread = recv(sd, buf, buflen, 0);
- if (nread < 0)
+ (void) m;
+
+ TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
+ if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
+
+ mDNSPlatformMemZero(sock, sizeof(TCPSocket));
+ sock->callback = mDNSNULL;
+ sock->fd = socket(AF_INET, SOCK_STREAM, 0);
+ sock->kqEntry.KQcallback= tcpKQSocketCallback;
+ sock->kqEntry.KQcontext = sock;
+ sock->kqEntry.KQtask = "mDNSPlatformTCPSocket";
+ sock->flags = flags;
+ sock->context = mDNSNULL;
+ sock->setup = mDNSfalse;
+ sock->handshakecomplete = mDNSfalse;
+ sock->connected = mDNSfalse;
+
+ if (sock->fd == -1)
{
- if (errno == EAGAIN) return 0; // no data available (call would block)
- LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno));
- return -1;
+ LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
+ freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
+ return(mDNSNULL);
}
- return nread;
+
+ // Bind it
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = port->NotAnInteger;
+ if (bind(sock->fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
+ { LogMsg("ERROR: bind %s", strerror(errno)); goto error; }
+
+ // Receive interface identifiers
+ const int on = 1; // "on" for setsockopt
+ if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
+ { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); goto error; }
+
+ memset(&addr, 0, sizeof(addr));
+ socklen_t len = sizeof(addr);
+ if (getsockname(sock->fd, (struct sockaddr*) &addr, &len) < 0)
+ { LogMsg("getsockname - %s", strerror(errno)); goto error; }
+
+ port->NotAnInteger = addr.sin_port;
+ return sock;
+
+error:
+ close(sock->fd);
+ freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
+ return(mDNSNULL);
}
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+ TCPConnectionCallback callback, void *context)
{
- int nsent = send(sd, msg, len, 0);
+ struct sockaddr_in saddr;
+ mStatus err = mStatus_NoError;
+
+ sock->callback = callback;
+ sock->context = context;
+ sock->setup = mDNSfalse;
+ sock->handshakecomplete = mDNSfalse;
+ sock->connected = mDNSfalse;
- if (nsent < 0)
+ (void) InterfaceID; //!!!KRS use this if non-zero!!!
+
+ if (dst->type != mDNSAddrType_IPv4)
{
- if (errno == EAGAIN) return 0; // blocked
- LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno));
- return -1;
+ LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
+ return mStatus_UnknownErr;
}
- return nsent;
- }
-// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
- {
- CFStringEncoding encoding = kCFStringEncodingUTF8;
- CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
- if (cfs)
+ mDNSPlatformMemZero(&saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = dstport.NotAnInteger;
+ saddr.sin_len = sizeof(saddr);
+ saddr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+
+ // Don't send if it would cause dial-on-demand connection initiation.
+ if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
{
- CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
- CFRelease(cfs);
+ debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
+ return mStatus_UnknownErr;
+ }
+
+ sock->kqEntry.KQcallback = tcpKQSocketCallback;
+ sock->kqEntry.KQcontext = sock;
+ sock->kqEntry.KQtask = "Outgoing TCP";
+
+ // Watch for connect complete (write is ready)
+ // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
+ if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
+ {
+ LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+ close(sock->fd);
+ return errno;
+ }
+
+ // Watch for incoming data
+ if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
+ {
+ LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+ close(sock->fd); // Closing the descriptor removes all filters from the kqueue
+ return errno;
+ }
+
+ if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
+ {
+ LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
+ return mStatus_UnknownErr;
+ }
+
+ // initiate connection wth peer
+ if (connect(sock->fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+ {
+ if (errno == EINPROGRESS) return mStatus_ConnPending;
+ LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock->fd, errno, strerror(errno));
+ close(sock->fd);
+ return mStatus_ConnFailed;
}
+
+ LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
+ // kQueue should notify us, but this LogMsg is to help track down if it doesn't
+ return err;
}
-// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
+// Why doesn't mDNSPlatformTCPAccept actually call accept() ?
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
{
- CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
- if (cfs)
+ mStatus err = mStatus_NoError;
+
+ TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
+ if (!sock) return(mDNSNULL);
+
+ memset(sock, 0, sizeof(*sock));
+ sock->fd = fd;
+ sock->flags = flags;
+
+ if (flags & kTCPSocketFlags_UseTLS)
{
- CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
- CFRelease(cfs);
+#ifndef NO_SECURITYFRAMEWORK
+ if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
+
+ err = tlsSetupSock(sock, mDNStrue);
+ if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
+
+ err = SSLSetCertificate(sock->tlsContext, ServerCerts);
+ if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
+#else
+ err = mStatus_UnsupportedErr;
+#endif /* NO_SECURITYFRAMEWORK */
}
+#ifndef NO_SECURITYFRAMEWORK
+exit:
+#endif
+
+ if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
+ return(sock);
}
-mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
{
- mDNSs32 val;
- CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
- if (!state) return mDNSfalse;
- if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
- return val ? mDNStrue : mDNSfalse;
+ if (sock)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ if (sock->tlsContext)
+ {
+ SSLClose(sock->tlsContext);
+ SSLDisposeContext(sock->tlsContext);
+ sock->tlsContext = NULL;
+ }
+#endif /* NO_SECURITYFRAMEWORK */
+ if (sock->fd != -1)
+ {
+ shutdown(sock->fd, 2);
+ close(sock->fd);
+ sock->fd = -1;
+ }
+
+ freeL("mDNSPlatformTCPCloseConnection", sock);
+ }
}
-mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *const regDomain, CFArrayRef *const browseDomains)
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
{
- char buf[MAX_ESCAPED_DOMAIN_NAME];
+ long nread = 0;
+ *closed = mDNSfalse;
- fqdn->c[0] = 0;
- regDomain->c[0] = 0;
- buf[0] = 0;
- *browseDomains = NULL;
-
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL, NULL);
- if (store)
+ if (sock->flags & kTCPSocketFlags_UseTLS)
{
- CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("Setup:/Network/DynamicDNS"));
- if (dict)
+#ifndef NO_SECURITYFRAMEWORK
+ if (!sock->handshakecomplete)
{
- CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
- if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
- {
- CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0); // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
- if (fqdnDict && DDNSSettingEnabled(fqdnDict))
- {
- CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
- if (name)
- {
- if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
- !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
- LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
- else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
- }
- }
- }
+ //LogMsg("mDNSPlatformReadTCP Starting SSLHandshake");
+ mStatus err = SSLHandshake(sock->tlsContext);
+ //if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete");
+ if (!err) sock->handshakecomplete = mDNStrue;
+ else if (err == errSSLWouldBlock) return(0);
+ else { LogMsg("Read SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; }
+ }
- CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
- if (regArray && CFArrayGetCount(regArray) > 0)
- {
- CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
- if (regDict && DDNSSettingEnabled(regDict))
- {
- CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
- if (name)
- {
- if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
- !MakeDomainNameFromDNSNameString(regDomain, buf) || !regDomain->c[0])
- LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
- else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf);
- }
- }
- }
- CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
- if (browseArray && CFArrayGetCount(browseArray) > 0)
- {
- CFRetain(browseArray);
- *browseDomains = browseArray;
- }
- CFRelease(dict);
+ //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
+ mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread);
+ //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
+ if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
+ else if (err && err != errSSLWouldBlock)
+ { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
+#else
+ nread = -1;
+ *closed = mDNStrue;
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+ else
+ {
+ static int CLOSEDcount = 0;
+ static int EAGAINcount = 0;
+ nread = recv(sock->fd, buf, buflen, 0);
+
+ if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters
+ else if (nread == 0)
+ {
+ *closed = mDNStrue;
+ if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); }
+ }
+ // else nread is negative -- see what kind of error we got
+ else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
+ else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno, strerror(errno)); nread = -1; }
+ else // errno is EAGAIN (EWOULDBLOCK) -- no data available
+ {
+ nread = 0;
+ if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
}
- CFRelease(store);
}
+
+ return nread;
}
-mDNSlocal void SetDDNSNameStatus(domainname *const dname, mStatus status)
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
{
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL, NULL);
- if (store)
- {
- char uname[MAX_ESCAPED_DOMAIN_NAME];
- ConvertDomainNameToCString(dname, uname);
- char *p = uname;
+ int nsent;
- while (*p)
- {
- *p = tolower(*p);
- if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
- p++;
- }
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ size_t processed;
+ mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
- // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
- // That single entity is a CFDictionary with name "HostNames".
- // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
- // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
- // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
- // The CFDictionary for each FQDN holds (at present) a single name/value pair,
- // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
-
- const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
- const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
- const CFStringRef StatusKeys[1] = { CFSTR("Status") };
- if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
- else
+ if (!err) nsent = (int) processed;
+ else if (err == errSSLWouldBlock) nsent = 0;
+ else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
+#else
+ nsent = -1;
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+ else
+ {
+ nsent = send(sock->fd, msg, len, 0);
+ if (nsent < 0)
{
- const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
- if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status);
- else
- {
- const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) };
- if (HostVals[0])
- {
- const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) };
- if (StateVals[0])
- {
- CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL);
- if (StateDict)
- {
- SCDynamicStoreSetValue(store, CFSTR("State:/Network/DynamicDNS"), StateDict);
- CFRelease(StateDict);
- }
- CFRelease(StateVals[0]);
- }
- CFRelease(HostVals[0]);
- }
- CFRelease(StatusVals[0]);
- }
- CFRelease(HostKeys[0]);
+ if (errno == EAGAIN) nsent = 0;
+ else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
}
- CFRelease(store);
}
+
+ return nsent;
+ }
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+ {
+ return sock->fd;
}
// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
-mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, const mDNSAddr *ifaddr, u_short sa_family)
+mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family)
{
+ const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
- CFSocketRef *c = (sa_family == AF_INET) ? &cp->cfsv4 : &cp->cfsv6;
- CFRunLoopSourceRef *r = (sa_family == AF_INET) ? &cp->rlsv4 : &cp->rlsv6;
+ KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
const int on = 1;
const int twofivefive = 255;
mStatus err = mStatus_NoError;
char *errstr = mDNSNULL;
- mDNSIPPort port = (mcast | m->CanReceiveUnicastOn5353) ? MulticastDNSPort : zeroIPPort;
-
- if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); }
- if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); }
-
- // Open the socket...
int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
- if (skt < 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
+ if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
// ... with a shared UDP port, if it's for multicast receiving
- if (port.NotAnInteger) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+ if (mDNSSameIPPort(port, MulticastDNSPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
if (sa_family == AF_INET)
// We want to receive destination addresses
err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
-
+
// We want to receive interface identifiers
err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
-
+
// We want to receive packet TTL value so we can check it
err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
// We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
-
- // Add multicast group membership on this interface, if it's for multicast receiving
- if (mcast)
- {
- struct in_addr addr = { ifaddr->ip.v4.NotAnInteger };
- struct ip_mreq imr;
- imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
- imr.imr_interface = addr;
- err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
- if (err < 0) { errstr = "setsockopt - IP_ADD_MEMBERSHIP"; goto fail; }
-
- // Specify outgoing interface too
- err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));
- if (err < 0) { errstr = "setsockopt - IP_MULTICAST_IF"; goto fail; }
- }
-
+
// Send unicast packets with TTL 255
err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
-
+
// And multicast packets with TTL 255 too
err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
// Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
- const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits));
if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; }
// We want to receive destination addresses and receive interface identifiers
err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
-
+
// We want to receive packet hop count value so we can check it
err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
-
- // We want to receive only IPv6 packets, without this option, we may
- // get IPv4 addresses as mapped addresses.
+
+ // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
+ // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
-
- if (mcast)
- {
- // Add multicast group membership on this interface, if it's for multicast receiving
- int interface_id = if_nametoindex(cp->info->ifa_name);
- struct ipv6_mreq i6mr;
- i6mr.ipv6mr_interface = interface_id;
- i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6;
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
- if (err < 0) { errstr = "setsockopt - IPV6_JOIN_GROUP"; goto fail; }
-
- // Specify outgoing interface too
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id));
- if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_IF"; goto fail; }
- }
-
+
// Send unicast packets with TTL 255
err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
-
+
// And multicast packets with TTL 255 too
err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
-
+
// Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?)
#ifdef IPV6_TCLASS
// Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate
err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass));
if (err < 0) { errstr = "setsockopt - IPV6_TCLASS"; goto fail; }
#endif
-
+
// Want to receive our own packets
err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
-
+
// And start listening for packets
struct sockaddr_in6 listening_sockaddr6;
- bzero(&listening_sockaddr6, sizeof(listening_sockaddr6));
+ mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
listening_sockaddr6.sin6_family = AF_INET6;
listening_sockaddr6.sin6_port = port.NotAnInteger;
listening_sockaddr6.sin6_flowinfo = 0;
-// listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
+ listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
listening_sockaddr6.sin6_scope_id = 0;
err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
if (err) { errstr = "bind"; goto fail; }
}
-
+
fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
+ fcntl(skt, F_SETFD, 1); // set close-on-exec
*s = skt;
- CFSocketContext myCFSocketContext = { 0, cp, NULL, NULL, NULL };
- *c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext);
- *r = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), *r, kCFRunLoopDefaultMode);
-
+ k->KQcallback = myKQSocketCallBack;
+ k->KQcontext = cp;
+ k->KQtask = "UDP packet reception";
+ KQueueSet(*s, EV_ADD, EVFILT_READ, k);
+
return(err);
-fail:
- LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
- if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
- NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904,
- "Alternatively, you can send email to radar-3387020@group.apple.com. "
+ fail:
+ // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
+ if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
+ LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno));
+
+ // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert
+ if (!strcmp(errstr, "bind") && mDNSSameIPPort(port, MulticastDNSPort) && errno == EADDRINUSE)
+ NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
+ "Congratulations, you've reproduced an elusive bug.\r"
+ "Please contact the current assignee of <rdar://problem/3814904>.\r"
+ "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
"If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
+
close(skt);
return(err);
}
+struct UDPSocket_struct
+ {
+ KQSocketSet ss;
+ };
+
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port)
+ {
+ mStatus err;
+ UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
+ if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
+ memset(p, 0, sizeof(UDPSocket));
+ p->ss.m = m;
+ p->ss.sktv4 = -1;
+ p->ss.sktv6 = -1;
+ err = SetupSocket(&p->ss, port, AF_INET);
+ if (err)
+ {
+ // In customer builds we don't want to log failures with port 5351, because this is a known issue
+ // of failing to bind to this port when Internet Sharing has already bound to it
+ if (mDNSSameIPPort(port, NATPMPPort))
+ LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
+ else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port));
+ freeL("UDPSocket", p);
+ return(mDNSNULL);
+ }
+ return(p);
+ }
+
+mDNSlocal void CloseSocketSet(KQSocketSet *ss)
+ {
+ if (ss->sktv4 != -1)
+ {
+ close(ss->sktv4);
+ ss->sktv4 = -1;
+ }
+ if (ss->sktv6 != -1)
+ {
+ close(ss->sktv6);
+ ss->sktv6 = -1;
+ }
+ }
+
+mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
+ {
+ CloseSocketSet(&sock->ss);
+ freeL("UDPSocket", sock);
+ }
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Key Management
+#endif
+
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
+ {
+ CFMutableArrayRef certChain = NULL;
+ if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
+ SecCertificateRef cert;
+ OSStatus err = SecIdentityCopyCertificate(identity, &cert);
+ if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
+ else
+ {
+ SecPolicySearchRef searchRef;
+ err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
+ if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
+ else
+ {
+ SecPolicyRef policy;
+ err = SecPolicySearchCopyNext(searchRef, &policy);
+ if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
+ else
+ {
+ CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
+ if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
+ else
+ {
+ SecTrustRef trust;
+ err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
+ if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
+ else
+ {
+ err = SecTrustEvaluate(trust, NULL);
+ if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
+ else
+ {
+ CFArrayRef rawCertChain;
+ CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
+ err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
+ if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
+ else
+ {
+ certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
+ if (!certChain) LogMsg("getCertChain: certChain is NULL");
+ else
+ {
+ // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
+ // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
+ CFArraySetValueAtIndex(certChain, 0, identity);
+ // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
+ if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
+ }
+ CFRelease(rawCertChain);
+ // Do not free statusChain:
+ // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
+ // certChain: Call the CFRelease function to release this object when you are finished with it.
+ // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
+ }
+ }
+ CFRelease(trust);
+ }
+ CFRelease(wrappedCert);
+ }
+ CFRelease(policy);
+ }
+ CFRelease(searchRef);
+ }
+ CFRelease(cert);
+ }
+ return certChain;
+ }
+#endif /* NO_SECURITYFRAMEWORK */
+
+mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
+ {
+#ifdef NO_SECURITYFRAMEWORK
+ return mStatus_UnsupportedErr;
+#else
+ SecIdentityRef identity = nil;
+ SecIdentitySearchRef srchRef = nil;
+ OSStatus err;
+
+ // search for "any" identity matching specified key use
+ // In this app, we expect there to be exactly one
+ err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
+ if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
+
+ err = SecIdentitySearchCopyNext(srchRef, &identity);
+ if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
+
+ if (CFGetTypeID(identity) != SecIdentityGetTypeID())
+ { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
+
+ // Found one. Call getCertChain to create the correct certificate chain.
+ ServerCerts = GetCertChain(identity);
+ if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
+
+ return mStatus_NoError;
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+
+mDNSexport void mDNSPlatformTLSTearDownCerts(void)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+
+// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
+ {
+ CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
+ if (cfs)
+ {
+ CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
+ CFRelease(cfs);
+ }
+ }
+
+// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
+ {
+ CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
+ if (cfs)
+ {
+ CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
+ CFRelease(cfs);
+ }
+ }
+
+mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
+ {
+ mDNSs32 val;
+ CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
+ if (!state) return mDNSfalse;
+ if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
+ return val ? mDNStrue : mDNSfalse;
+ }
+
mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
{
if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
if (sa->sa_family == AF_INET6)
{
struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
- ip->type = mDNSAddrType_IPv6;
+ // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
+ // value into the second word of the IPv6 link-local address, so they can just
+ // pass around IPv6 address structures instead of full sockaddr_in6 structures.
+ // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
+ // To work around this we always whack the second word of any IPv6 link-local address back to zero.
if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
+ ip->type = mDNSAddrType_IPv6;
ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
return(mStatus_NoError);
}
return(eth);
}
+// Returns pointer to newly created NetworkInterfaceInfoOSX object, or
+// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
+// may return NULL if out of memory (unlikely) or parameters are invalid for some reason
+// (e.g. sa_family not AF_INET or AF_INET6)
mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
{
mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
{
debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
(*p)->Exists = mDNStrue;
+ // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
+ if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
return(*p);
}
NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
if (!i) return(mDNSNULL);
- bzero(i, sizeof(NetworkInterfaceInfoOSX));
+ mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
i->ifa_name = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1);
if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); }
- strcpy(i->ifa_name, ifa->ifa_name);
+ strcpy(i->ifa_name, ifa->ifa_name); // This is safe because we know we allocated i->ifa_name with sufficient space
i->ifinfo.InterfaceID = mDNSNULL;
i->ifinfo.ip = ip;
i->ifinfo.mask = mask;
- strncpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
+ strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
i->ifinfo.Advertise = m->AdvertiseLocalAddresses;
i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
-
+
i->next = mDNSNULL;
i->Exists = mDNStrue;
+ i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
i->LastSeen = utc;
+ i->Flashing = mDNSfalse;
+ i->Occulting = mDNSfalse;
i->scope_id = scope_id;
i->BSSID = bssid;
i->sa_family = ifa->ifa_addr->sa_family;
- i->Multicast = (ifa->ifa_flags & IFF_MULTICAST) && !(ifa->ifa_flags & IFF_POINTOPOINT);
-
- i->ss.m = m;
- i->ss.info = i;
- i->ss.sktv4 = i->ss.sktv6 = -1;
- i->ss.cfsv4 = i->ss.cfsv6 = NULL;
- i->ss.rlsv4 = i->ss.rlsv6 = NULL;
+ i->ifa_flags = ifa->ifa_flags;
*p = i;
return(i);
}
-mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
+#if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
+mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
+ {
+ NetworkInterfaceInfoOSX *i;
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
+ if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4))
+ return(i);
+ return(mDNSNULL);
+ }
+#endif
+
+#if APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - AutoTunnel
+#endif
+
+#define kRacoonPort 4500
+
+static mDNSBool AnonymousRacoonConfig = mDNSfalse;
+
+// MUST be called with lock held
+mDNSlocal mDNSBool TunnelServers(mDNS *const m)
+ {
+ ServiceRecordSet *p;
+ for (p = m->ServiceRegistrations; p; p = p->uDNS_next)
+ {
+ DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, p->RR_SRV.resrec.name);
+ if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
+ }
+ return(mDNSfalse);
+ }
+
+// MUST be called with lock held
+mDNSlocal mDNSBool TunnelClients(mDNS *const m)
+ {
+ ClientTunnel *p;
+ for (p = m->TunnelClients; p; p = p->next)
+ if (p->q.ThisQInterval < 0)
+ return(mDNStrue);
+ return(mDNSfalse);
+ }
+
+mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
+ {
+ if (!info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info))
+ {
+ LogOperation("RegisterAutoTunnelRecords %##s", info->AutoTunnelService.namestorage.c);
+ mStatus err;
+ info->AutoTunnelService.resrec.rdata->u.srv.port = info->AutoTunnelNAT.ExternalPort;
+ info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
+ err = mDNS_Register(m, &info->AutoTunnelService);
+ if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
+
+ info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
+ mDNS_Lock(m);
+ mDNS_AddDynDNSHostName(m, &info->AutoTunnelTarget.namestorage, mDNSNULL, info);
+ mDNS_Unlock(m);
+
+ if (info->AutoTunnelHostRecord.namestorage.c[0] == 0)
+ {
+ AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
+ AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
+ }
+ info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
+ err = mDNS_Register(m, &info->AutoTunnelHostRecord);
+ if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
+
+ info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
+ err = mDNS_Register(m, &info->AutoTunnelDeviceInfo);
+ if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+
+ LogMsg("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
+ info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort),
+ info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
+ }
+ }
+
+mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
+ {
+ LogOperation("DeregisterAutoTunnelRecords %##s", info->AutoTunnelService.namestorage.c);
+ if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
+ {
+ mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
+ if (err)
+ {
+ info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
+ LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
+ }
+
+ mDNS_Lock(m);
+ mDNS_RemoveDynDNSHostName(m, &info->AutoTunnelTarget.namestorage);
+ mDNS_Unlock(m);
+ }
+
+ if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
+ {
+ mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
+ if (err)
+ {
+ info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
+ LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
+ }
+ info->AutoTunnelHostRecord.namestorage.c[0] = 0;
+ }
+
+ if (info->AutoTunnelDeviceInfo.resrec.RecordType > kDNSRecordTypeDeregistering)
+ {
+ mStatus err = mDNS_Deregister(m, &info->AutoTunnelDeviceInfo);
+ if (err)
+ {
+ info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
+ LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+ }
+ }
+ }
+
+mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+ {
+ DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
+ if (result == mStatus_MemFree)
+ {
+ LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
+ RegisterAutoTunnelRecords(m,info);
+ }
+ }
+
+mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
+ {
+ DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext;
+ LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %##s", n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), info->AutoTunnelService.namestorage.c);
+
+ m->NextSRVUpdate = m->timenow;
+ DeregisterAutoTunnelRecords(m,info);
+ RegisterAutoTunnelRecords(m,info);
+
+ // Determine whether we need racoon to accept incoming connections
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->AutoTunnel && !info->deltime && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort))
+ break;
+ mDNSBool needRacoonConfig = info != mDNSNULL;
+ if (needRacoonConfig != AnonymousRacoonConfig)
+ {
+ AnonymousRacoonConfig = needRacoonConfig;
+ // Create or revert configuration file, and start (or SIGHUP) Racoon
+ (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, info ? info->b64keydata : "");
+ }
+ }
+
+// Before SetupLocalAutoTunnelInterface_internal is called,
+// m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
+// Must be called with the lock held
+mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m)
+ {
+ LogOperation("SetupLocalAutoTunnelInterface");
+
+ // 1. Configure the local IPv6 address
+ if (!m->AutoTunnelHostAddrActive)
+ {
+ m->AutoTunnelHostAddrActive = mDNStrue;
+ LogMsg("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
+ (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
+ }
+
+ // 2. If we have at least one server (pending) listening, publish our records
+ if (TunnelServers(m))
+ {
+ DomainAuthInfo *info;
+ for (info = m->AuthInfoList; info; info = info->next)
+ {
+ if (info->AutoTunnel && !info->deltime && !info->AutoTunnelNAT.clientContext)
+ {
+ // 1. Set up our address record for the internal tunnel address
+ // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
+ mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+ info->AutoTunnelHostRecord.namestorage.c[0] = 0;
+ info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr;
+
+ // 2. Set up device info record
+ mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
+ mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+ ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
+ mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
+ mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
+ info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len; // "model=" plus the device string
+ info->AutoTunnelDeviceInfo.resrec.rdlength = 7 + len; // One extra for the length byte at the start of the string
+
+ // 3. Set up our address record for the external tunnel address
+ // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
+ mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+ info->AutoTunnelTarget.namestorage.c[0] = 0;
+ AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->AutoTunnelLabel);
+ AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
+
+ // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
+ mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+ AssignDomainName(&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
+ AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
+ AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
+ info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
+ info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
+ AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
+
+ // Try to get a NAT port mapping for the AutoTunnelService
+ info->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
+ info->AutoTunnelNAT.clientContext = info;
+ info->AutoTunnelNAT.Protocol = NATOp_MapUDP;
+ info->AutoTunnelNAT.IntPort = mDNSOpaque16fromIntVal(kRacoonPort);
+ info->AutoTunnelNAT.RequestedPort = mDNSOpaque16fromIntVal(kRacoonPort);
+ info->AutoTunnelNAT.NATLease = 0;
+ mStatus err = mDNS_StartNATOperation_internal(m, &info->AutoTunnelNAT);
+ if (err) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err);
+ }
+ }
+ }
+ }
+
+mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
+ {
+ return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, tun->loc_outer.b, kRacoonPort, tun->rmt_inner.b, tun->rmt_outer.b, mDNSVal16(tun->rmt_outer_port), tun->b64keydata));
+ }
+
+// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
+#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
+
+mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
+ {
+ DNSQuestion *q = m->Questions;
+ while (q)
+ {
+ if (q->NoAnswer == NoAnswer_Suspended && q->qtype == kDNSType_AAAA && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
+ {
+ LogOperation("Restart %##s", q->qname.c);
+ mDNSQuestionCallback *tmp = q->QuestionCallback;
+ q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
+ mDNS_StopQuery(m, q);
+ mDNS_StartQuery(m, q);
+ q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
+ if (!success) q->NoAnswer = NoAnswer_Fail;
+ // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too.
+ // In general we have to assume that the question list might have changed in arbitrary ways.
+ // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
+ // already in use. The safest solution is just to go back to the start of the list and start again.
+ // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
+ // just one suspended question, so it's really a 2n algorithm.
+ q = m->Questions;
+ }
+ else
+ q = q->next;
+ }
+ }
+
+mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
{
- NetworkInterfaceInfoOSX *i;
- for (i = m->p->InterfaceList; i; i = i->next)
- if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
- if (!(i->ifinfo.ip.ip.v4.b[0] == 169 && i->ifinfo.ip.ip.v4.b[1] == 254))
- return(i);
- return(mDNSNULL);
+ ClientTunnel **p = &m->TunnelClients;
+ while (*p != tun && *p) p = &(*p)->next;
+ if (*p) *p = tun->next;
+ ReissueBlockedQuestions(m, &tun->dstname, success);
+ freeL("ClientTunnel", tun);
}
+mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+ {
+ ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
+ LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
+
+ if (!AddRecord) return;
+ mDNS_StopQuery(m, question);
+
+ if (!answer->rdlength)
+ {
+ LogOperation("AutoTunnelCallback NXDOMAIN %##s", question->qname.c);
+ UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
+ return;
+ }
+
+ if (question->qtype == kDNSType_AAAA)
+ {
+ if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
+ {
+ LogOperation("AutoTunnelCallback: supressing tunnel to self %.16a", &answer->rdata->u.ipv6);
+ UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
+ return;
+ }
+
+ tun->rmt_inner = answer->rdata->u.ipv6;
+ LogOperation("AutoTunnelCallback: dst host %.16a", &tun->rmt_inner);
+ AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
+ AppendDomainName(&question->qname, &tun->dstname);
+ question->qtype = kDNSType_SRV;
+ mDNS_StartQuery(m, &tun->q);
+ }
+ else if (question->qtype == kDNSType_SRV)
+ {
+ LogOperation("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
+ AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
+ tun->rmt_outer_port = answer->rdata->u.srv.port;
+ question->qtype = kDNSType_A;
+ mDNS_StartQuery(m, &tun->q);
+ }
+ else if (question->qtype == kDNSType_A)
+ {
+ ClientTunnel *old = mDNSNULL;
+ LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
+ question->ThisQInterval = -1; // So we know this tunnel setup has completed
+ tun->rmt_outer = answer->rdata->u.ipv4;
+ tun->loc_inner = m->AutoTunnelHostAddr;
+ mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
+ tmpDst.ip.v4 = tun->rmt_outer;
+ mDNSAddr tmpSrc = zeroAddr;
+ FindSourceAddrForIP(&tmpDst, &tmpSrc);
+ if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
+ else tun->loc_outer = m->AdvertisedV4.ip.v4;
+
+ ClientTunnel **p = &tun->next;
+ mDNSBool needSetKeys = mDNStrue;
+ while (*p)
+ {
+ if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
+ else
+ {
+ LogOperation("Found existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
+ old = *p;
+ *p = old->next;
+ if (old->q.ThisQInterval >= 0) mDNS_StopQuery(m, &old->q);
+ else if (!mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
+ !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
+ !mDNSSameIPv6Address(old->rmt_inner, tun->rmt_inner) ||
+ !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
+ !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
+ {
+ LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
+ AutoTunnelSetKeys(old, mDNSfalse);
+ }
+ else needSetKeys = mDNSfalse;
+
+ freeL("ClientTunnel", old);
+ }
+ }
+
+ if (needSetKeys) LogOperation("New AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
+
+ if (m->AutoTunnelHostAddr.b[0]) { mDNS_Lock(m); SetupLocalAutoTunnelInterface_internal(m); mDNS_Unlock(m); };
+
+ mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
+ // Kick off any questions that were held pending this tunnel setup
+ ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
+ }
+ else
+ LogMsg("AutoTunnelCallback: Unknown question %p", question);
+ }
+
+// Must be called with the lock held
+mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
+ {
+ ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
+ if (!p) return;
+ AssignDomainName(&p->dstname, &q->qname);
+ p->markedForDeletion = mDNSfalse;
+ p->loc_inner = zerov6Addr;
+ p->loc_outer = zerov4Addr;
+ p->rmt_inner = zerov6Addr;
+ p->rmt_outer = zerov4Addr;
+ p->rmt_outer_port = zeroIPPort;
+ mDNS_snprintf(p->b64keydata, sizeof(p->b64keydata), "%s", q->AuthInfo->b64keydata);
+ p->next = m->TunnelClients;
+ m->TunnelClients = p; // Intentionally build list in reverse order
+
+ p->q.InterfaceID = mDNSInterface_Any;
+ p->q.Target = zeroAddr;
+ AssignDomainName(&p->q.qname, &q->qname);
+ p->q.qtype = kDNSType_AAAA;
+ p->q.qclass = kDNSClass_IN;
+ p->q.LongLived = mDNSfalse;
+ p->q.ExpectUnique = mDNStrue;
+ p->q.ForceMCast = mDNSfalse;
+ p->q.ReturnIntermed = mDNStrue;
+ p->q.QuestionCallback = AutoTunnelCallback;
+ p->q.QuestionContext = p;
+
+ LogOperation("AddNewClientTunnel start %##s (%s)%s", &p->q.qname.c, DNSTypeName(p->q.qtype), q->LongLived ? " LongLived" : "");
+ mDNS_StartQuery_internal(m, &p->q);
+ }
+
+#endif // APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Power State & Configuration Change Management
+#endif
+
mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
{
mDNSBool foundav4 = mDNSfalse;
struct ifaddrs *v6Loopback = NULL;
mDNSEthAddr PrimaryMAC = zeroEthAddr;
char defaultname[32];
+#ifndef NO_IPV6
int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
- if (InfoSocket < 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
+ if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
+#endif
if (m->SleepState) ifa = NULL;
while (ifa)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr))
- mDNSPlatformMemCopy(sdl->sdl_data + sdl->sdl_nlen, PrimaryMAC.b, 6);
+ mDNSPlatformMemCopy(PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
}
if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
else
{
int ifru_flags6 = 0;
+#ifndef NO_IPV6
if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
struct in6_ifreq ifr6;
- bzero((char *)&ifr6, sizeof(ifr6));
- strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
+ mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
+ strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = *sin6;
if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
}
+#endif
if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
{
if (ifa->ifa_flags & IFF_LOOPBACK)
else
{
NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
- if (i && i->Multicast)
+ if (i && MulticastInterface(i))
{
if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
else foundav6 = mDNStrue;
ifa = ifa->ifa_next;
}
- // For efficiency, we don't register a loopback interface when other interfaces of that family are available
+ // For efficiency, we don't register a loopback interface when other interfaces of that family are available
if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
// Now the list is complete, set the McastTxRx setting for each interface.
- // We always send and receive using IPv4.
- // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
- // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
- // which means there's a good chance that most or all the other devices on that network should also have v4.
- // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half.
- // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
- // so we are willing to make that sacrifice.
NetworkInterfaceInfoOSX *i;
for (i = m->p->InterfaceList; i; i = i->next)
if (i->Exists)
{
- mDNSBool txrx = i->Multicast && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
+ mDNSBool txrx = MulticastInterface(i);
+#if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
+ txrx = txrx && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id));
+#endif
if (i->ifinfo.McastTxRx != txrx)
{
i->ifinfo.McastTxRx = txrx;
i->Exists = 2; // State change; need to deregister and reregister this interface
}
}
+
+#ifndef NO_IPV6
if (InfoSocket >= 0) close(InfoSocket);
+#endif
- mDNS_snprintf(defaultname, sizeof(defaultname), "Macintosh-%02X%02X%02X%02X%02X%02X",
+ // If we haven't set up AutoTunnelHostAddr yet, do it now
+ if (!mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0)
+ {
+ m->AutoTunnelHostAddr.b[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193)
+ m->AutoTunnelHostAddr.b[0x1] = mDNSRandom(255);
+ m->AutoTunnelHostAddr.b[0x2] = mDNSRandom(255);
+ m->AutoTunnelHostAddr.b[0x3] = mDNSRandom(255);
+ m->AutoTunnelHostAddr.b[0x4] = mDNSRandom(255);
+ m->AutoTunnelHostAddr.b[0x5] = mDNSRandom(255);
+ m->AutoTunnelHostAddr.b[0x6] = mDNSRandom(255);
+ m->AutoTunnelHostAddr.b[0x7] = mDNSRandom(255);
+ m->AutoTunnelHostAddr.b[0x8] = PrimaryMAC.b[0] ^ 0x02; // See RFC 3513, Appendix A for explanation
+ m->AutoTunnelHostAddr.b[0x9] = PrimaryMAC.b[1];
+ m->AutoTunnelHostAddr.b[0xA] = PrimaryMAC.b[2];
+ m->AutoTunnelHostAddr.b[0xB] = 0xFF;
+ m->AutoTunnelHostAddr.b[0xC] = 0xFE;
+ m->AutoTunnelHostAddr.b[0xD] = PrimaryMAC.b[3];
+ m->AutoTunnelHostAddr.b[0xE] = PrimaryMAC.b[4];
+ m->AutoTunnelHostAddr.b[0xF] = PrimaryMAC.b[5];
+ m->AutoTunnelLabel.c[0] = mDNS_snprintf((char*)m->AutoTunnelLabel.c+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
+ m->AutoTunnelHostAddr.b[0x8], m->AutoTunnelHostAddr.b[0x9], m->AutoTunnelHostAddr.b[0xA], m->AutoTunnelHostAddr.b[0xB],
+ m->AutoTunnelHostAddr.b[0xC], m->AutoTunnelHostAddr.b[0xD], m->AutoTunnelHostAddr.b[0xE], m->AutoTunnelHostAddr.b[0xF]);
+ LogOperation("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c);
+ }
+
+ #ifndef kDefaultLocalHostNamePrefix
+ #define kDefaultLocalHostNamePrefix "Macintosh"
+ #endif
+ mDNS_snprintf(defaultname, sizeof(defaultname), kDefaultLocalHostNamePrefix "-%02X%02X%02X%02X%02X%02X",
PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]);
// Set up the nice label
MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
}
- if (SameDomainLabel(m->p->usernicelabel.c, nicelabel.c))
+ // We use a case-sensitive comparison here because even though changing the capitalization
+ // of the name alone is not significant to DNS, it's still a change from the user's point of view
+ if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
else
{
- debugf("Updating m->nicelabel to %#s", nicelabel.c);
+ if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
+ LogMsg("User updated Computer Name from %#s to %#s", m->p->usernicelabel.c, nicelabel.c);
m->p->usernicelabel = m->nicelabel = nicelabel;
}
- if (SameDomainLabel(m->p->userhostlabel.c, hostlabel.c))
+ if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
else
{
- debugf("Updating m->hostlabel to %#s", hostlabel.c);
+ if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
+ LogMsg("User updated Local Hostname from %#s to %#s", m->p->userhostlabel.c, hostlabel.c);
m->p->userhostlabel = m->hostlabel = hostlabel;
mDNS_SetFQDN(m);
}
return(mStatus_NoError);
}
+#if LogAllOperations || MDNS_DEBUGMSGS
+// Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
+// Returns -1 if all the one-bits are not contiguous
mDNSlocal int CountMaskBits(mDNSAddr *mask)
{
int i = 0, bits = 0;
while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
return(bits);
}
+#endif
// returns count of non-link local V4 addresses registered
mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
NetworkInterfaceInfo *n = &i->ifinfo;
NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name);
-
+
if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) // Sanity check
{
LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary);
n->InterfaceID = mDNSNULL;
}
-
+
if (!n->InterfaceID)
{
// NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
// If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
// If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
// If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
- mDNSBool flapping = (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
- mDNS_RegisterInterface(m, n, flapping ? mDNSPlatformOneSecond * 5 : 0);
- if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
- LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s",
+ i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
+ mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
+ if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
+ LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
- flapping ? " (Flapping)" : "", n->InterfaceActive ? " (Primary)" : "");
+ i->Flashing ? " (Flashing)" : "",
+ i->Occulting ? " (Occulting)" : "",
+ n->InterfaceActive ? " (Primary)" : "");
}
-
+
if (!n->McastTxRx)
debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip);
else
{
- if (i->sa_family == AF_INET && primary->ss.sktv4 == -1)
+ if (i->sa_family == AF_INET)
{
- mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET);
- if (err == 0) debugf("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
- else LogMsg("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
+ struct ip_mreq imr;
+ primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger;
+ imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
+ imr.imr_interface = primary->ifa_v4addr;
+ mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
+ // Joining same group twice can give "Address already in use" error -- no need to report that
+ if (err < 0 && errno != EADDRINUSE)
+ LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno));
}
-
- if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1)
+#ifndef NO_IPV6
+ if (i->sa_family == AF_INET6)
{
- mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET6);
- if (err == 0) debugf("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
- else LogMsg("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
+ struct ipv6_mreq i6mr;
+ i6mr.ipv6mr_interface = primary->scope_id;
+ i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
+ mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
+ // Joining same group twice can give "Address already in use" error -- no need to report that
+ if (err < 0 && errno != EADDRINUSE)
+ LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno));
}
+#endif
}
}
return count;
}
}
-mDNSlocal void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls, CFSocketRef cfs)
- {
- // Note: CFSocketInvalidate also closes the underlying socket for us
- // Comments show retain counts (obtained via CFGetRetainCount()) after each call. rls 3 cfs 3
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); // rls 2 cfs 3
- CFRelease(rls); // rls ? cfs 3
- CFSocketInvalidate(cfs); // rls ? cfs 1
- CFRelease(cfs); // rls ? cfs ?
- }
-
-mDNSlocal void CloseSocketSet(CFSocketSet *ss)
- {
- // Note: MUST NOT close the underlying native BSD sockets.
- // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately,
- // because it first has to unhook the sockets from its select() call, before it can safely close them.
- if (ss->cfsv4) CloseRunLoopSourceSocket(ss->rlsv4, ss->cfsv4);
- if (ss->cfsv6) CloseRunLoopSourceSocket(ss->rlsv6, ss->cfsv6);
- ss->sktv4 = ss->sktv6 = -1;
- ss->cfsv4 = ss->cfsv6 = NULL;
- ss->rlsv4 = ss->rlsv6 = NULL;
- }
-
// returns count of non-link local V4 addresses deregistered
mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
{
int count = 0;
for (i = m->p->InterfaceList; i; i = i->next)
{
- // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it
+ // If this interface is no longer active, or its InterfaceID is changing, deregister it
NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family);
if (i->ifinfo.InterfaceID)
if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
{
- LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s",
+ i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
+ LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s",
i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
- &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), i->ifinfo.InterfaceActive ? " (Primary)" : "");
- mDNS_DeregisterInterface(m, &i->ifinfo);
- if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
+ &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
+ i->Flashing ? " (Flashing)" : "",
+ i->Occulting ? " (Occulting)" : "",
+ i->ifinfo.InterfaceActive ? " (Primary)" : "");
+ mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
+ if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
i->ifinfo.InterfaceID = mDNSNULL;
// NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
// so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
while (*p)
{
i = *p;
- // 2. Close all our CFSockets. We'll recreate them later as necessary.
- // (We may have previously had both v4 and v6, and we may not need both any more.)
- CloseSocketSet(&i->ss);
- // 3. If no longer active, delete interface from list and free memory
+ // If no longer active, delete interface from list and free memory
if (!i->Exists)
{
if (i->LastSeen == utc) i->LastSeen = utc - 1;
return count;
}
-mDNSlocal mStatus GetDNSConfig(void **result)
+mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
{
-#if MDNS_NO_DNSINFO
- static int MessageShown = 0;
- if (!MessageShown) { MessageShown = 1; LogMsg("Note: Compiled without Apple-specific Split-DNS support"); }
- *result = NULL;
- return mStatus_UnsupportedErr;
-#else
-
- *result = dns_configuration_copy();
-
- if (!*result)
+ DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
+ if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
+ else
{
- // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
- if (mDNSMacOSXSystemBuildNumber(NULL) < 8) return mStatus_UnsupportedErr;
-
- // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
- // Apparently this is expected behaviour -- "not a bug".
- // Accordingly, we suppress syslog messages for the first three minutes after boot.
- // If we are still getting failures after three minutes, then we log them.
- if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return mStatus_NoError;
-
- LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
- return mStatus_UnknownErr;
+ dnle->next = mDNSNULL;
+ dnle->uid = uid;
+ AssignDomainName(&dnle->name, name);
+ **List = dnle;
+ *List = &dnle->next;
}
- return mStatus_NoError;
-#endif // MDNS_NO_DNSINFO
}
-mDNSlocal mStatus RegisterSplitDNS(mDNS *m, int *nAdditions, int *nDeletions)
+mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
{
- (void)m; // unused on 10.3 systems
- void *v;
- *nAdditions = *nDeletions = 0;
- mStatus err = GetDNSConfig(&v);
+ int i;
+ char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
+ domainname d;
-#if !MDNS_NO_DNSINFO
- if (!err && v)
- {
- int i;
- DNSServer *p;
- dns_config_t *config = v; // use void * to allow compilation on 10.3 systems
- mDNS_Lock(m);
- p = m->uDNS_info.Servers;
- while (p) { p->del = mDNStrue; p = p->next; } // mark all for deletion
-
- LogOperation("RegisterSplitDNS: Registering %d resolvers", config->n_resolver);
- for (i = 0; i < config->n_resolver; i++)
- {
- int j, n;
- domainname d;
- dns_resolver_t *r = config->resolver[i];
- if (r->port == MulticastDNSPort.NotAnInteger) continue; // ignore configurations for .local
- if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
- else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
-
- // check if this is the lowest-weighted server for the domain
- for (j = 0; j < config->n_resolver; j++)
- {
- dns_resolver_t *p = config->resolver[j];
- if (p->port == MulticastDNSPort.NotAnInteger) continue;
- if (p->search_order <= r->search_order)
- {
- domainname tmp;
- if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
- else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
- if (SameDomainName(&d, &tmp))
- if (p->search_order < r->search_order || j < i) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
- }
- }
- if (j < config->n_resolver) // found a lower-weighted resolver for this domain
- { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); continue; }
- // we're using this resolver - find the first IPv4 address
- for (n = 0; n < r->n_nameserver; n++)
- {
- if (r->nameserver[n]->sa_family == AF_INET && !AddrRequiresPPPConnection(r->nameserver[n]))
- {
- // %%% This should use mDNS_AddDNSServer() instead of duplicating functionality here
- mDNSAddr saddr;
- if (SetupAddr(&saddr, r->nameserver[n])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
- // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
- debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i, saddr.ip.v4.b[0], saddr.ip.v4.b[1], saddr.ip.v4.b[2], saddr.ip.v4.b[3], d.c);
- p = m->uDNS_info.Servers;
- while (p)
- {
- if (mDNSSameAddress(&p->addr, &saddr) && SameDomainName(&p->domain, &d)) { p->del = mDNSfalse; break; }
- else p = p->next;
- }
- if (!p)
- {
- p = mallocL("DNSServer", sizeof(*p));
- if (!p) { LogMsg("Error: malloc"); mDNS_Unlock(m); return mStatus_UnknownErr; }
- p->addr = saddr;
- p->del = mDNSfalse;
- p->teststate = DNSServer_Untested;
- AssignDomainName(&p->domain, &d);
- p->next = m->uDNS_info.Servers;
- m->uDNS_info.Servers = p;
- (*nAdditions)++;
- }
- break; // !!!KRS if we ever support round-robin servers, don't break here
- }
- }
- }
+ // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
+ if (fqdn) fqdn->c[0] = 0;
+ if (RegDomains ) *RegDomains = NULL;
+ if (BrowseDomains) *BrowseDomains = NULL;
+
+ LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s",
+ setservers ? " setservers" : "",
+ setsearch ? " setsearch" : "",
+ fqdn ? " fqdn" : "",
+ RegDomains ? " RegDomains" : "",
+ BrowseDomains ? " BrowseDomains" : "");
- // remove all servers marked for deletion
- DNSServer **s = &m->uDNS_info.Servers;
- while (*s)
+ // Add the inferred address-based configuration discovery domains
+ // (should really be in core code I think, not platform-specific)
+ if (setsearch)
+ {
+ struct ifaddrs *ifa = myGetIfAddrs(1);
+ while (ifa)
{
- if ((*s)->del)
+ mDNSAddr a, n;
+ if (ifa->ifa_addr->sa_family == AF_INET &&
+ ifa->ifa_netmask &&
+ !(ifa->ifa_flags & IFF_LOOPBACK) &&
+ !SetupAddr(&a, ifa->ifa_addr) &&
+ !SetupAddr(&n, ifa->ifa_netmask) &&
+ !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
{
- p = *s;
- *s = (*s)->next;
- freeL("DNSServer", p);
- (*nDeletions)--;
+ // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
+ mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
+ a.ip.v4.b[2] & n.ip.v4.b[2],
+ a.ip.v4.b[1] & n.ip.v4.b[1],
+ a.ip.v4.b[0] & n.ip.v4.b[0]);
+ mDNS_AddSearchDomain_CString(buf);
}
- else s = &(*s)->next;
+ ifa = ifa->ifa_next;
}
- mDNS_Unlock(m);
- dns_configuration_free(config);
}
-#endif
-
- return err;
- }
-
-mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
- {
- int i, count;
- CFArrayRef values;
- char buf[256];
- mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 0 } } } };
- CFStringRef s;
- mDNS_DeleteDNSServers(m); // deregister orig list
- values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
- if (!values) return mStatus_NoError;
-
- count = CFArrayGetCount(values);
- for (i = 0; i < count; i++)
+#ifndef MDNS_NO_DNSINFO
+ if (setservers || setsearch)
{
- s = CFArrayGetValueAtIndex(values, i);
- if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; }
- if (!CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8))
- {
- LogMsg("ERROR: RegisterNameServers - CFStringGetCString");
- continue;
- }
- if (!inet_aton(buf, (struct in_addr *)saddr.ip.v4.b))
- {
- LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf);
- continue;
- }
- LogOperation("RegisterNameServers: Adding %#a", &saddr);
- mDNS_AddDNSServer(m, &saddr, NULL);
- }
- return mStatus_NoError;
- }
-
-mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
- {
- (void)m; // unused
- ARListElem *elem = rr->RecordContext;
- if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
- }
-
-mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
- {
- SearchListElem *slElem = question->QuestionContext;
- ARListElem *arElem, *ptr, *prev;
- AuthRecord *dereg;
- const char *name;
- mStatus err;
-
- if (AddRecord)
- {
- arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
- if (!arElem) { LogMsg("ERROR: malloc"); return; }
- mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
- if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
- else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
- else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
- else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
- else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
- else { LogMsg("FoundDomain - unknown question"); return; }
-
- MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
- AppendDNSNameString (arElem->ar.resrec.name, "local");
- AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
- err = mDNS_Register(m, &arElem->ar);
- if (err)
+ dns_config_t *config = dns_configuration_copy();
+ if (!config)
{
- LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
- freeL("FoundDomain - arElem", arElem);
- return;
+ // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
+ // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
+ // Apparently this is expected behaviour -- "not a bug".
+ // Accordingly, we suppress syslog messages for the first three minutes after boot.
+ // If we are still getting failures after three minutes, then we log them.
+ if (mDNSMacOSXSystemBuildNumber(NULL) > 7 && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
+ LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
}
- arElem->next = slElem->AuthRecs;
- slElem->AuthRecs = arElem;
- }
- else
- {
- ptr = slElem->AuthRecs;
- prev = NULL;
- while (ptr)
+ else
{
- if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
+ LogOperation("mDNSPlatformSetDNSConfig: Registering %d resolvers", config->n_resolver);
+ if (setservers)
{
- debugf("Deregistering PTR %##s -> %##s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
- dereg = &ptr->ar;
- if (prev) prev->next = ptr->next;
- else slElem->AuthRecs = ptr->next;
- ptr = ptr->next;
- err = mDNS_Deregister(m, dereg);
- if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
+ for (i = 0; i < config->n_resolver; i++)
+ {
+ int j, n;
+ dns_resolver_t *r = config->resolver[i];
+ // Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port)
+ // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
+ // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
+ if (r->port == 5353) continue;
+ if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
+ else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
+
+ for (j = 0; j < config->n_resolver; j++) // check if this is the lowest-weighted server for the domain
+ {
+ dns_resolver_t *p = config->resolver[j];
+ if (p->port == 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order"
+ if (p->search_order <= r->search_order)
+ {
+ domainname tmp;
+ if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
+ else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
+ if (SameDomainName(&d, &tmp))
+ if (p->search_order < r->search_order || j < i) break; // if equal weights, pick first in list, otherwise pick lower-weight (p)
+ }
+ }
+ if (j < config->n_resolver) // found a lower-weighted resolver for this domain
+ debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j);
+ else
+ {
+ mDNSInterfaceID interface = mDNSInterface_Any;
+ int disabled = 0;
+
+ // DNS server option parsing
+ if (r->options != NULL)
+ {
+ char *nextOption = r->options;
+ char *currentOption = NULL;
+ while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0)
+ {
+ // The option may be in the form of interface=xxx where xxx is an interface name.
+ if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0)
+ {
+ NetworkInterfaceInfoOSX *i;
+ char ifname[IF_NAMESIZE+1];
+ mDNSu32 ifindex = 0;
+ // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
+ // This allows us to block these special queries from going out on the wire.
+ strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname));
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname); continue; }
+ LogOperation("%s: Interface specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex);
+ // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
+ // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->ifinfo.InterfaceID && i->scope_id == ifindex) break;
+ if (i != NULL) interface = i->ifinfo.InterfaceID;
+ if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; }
+ }
+ }
+ }
+ for (n = 0; n < r->n_nameserver; n++)
+ if (r->nameserver[n]->sa_family == AF_INET && (interface || disabled || !AddrRequiresPPPConnection(r->nameserver[n])))
+ {
+ mDNSAddr saddr;
+ // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
+ debugf("Adding dns server from slot %d %#a for domain %##s", i, &saddr, d.c);
+ if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address");
+ else
+ {
+ DNSServer *s = mDNS_AddDNSServer(m, &d, mDNSInterface_Any, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort);
+ if (s && disabled) s->teststate = DNSServer_Disabled;
+ }
+ }
+ }
+ }
}
- else
+ if (setsearch)
{
- prev = ptr;
- ptr = ptr->next;
+ // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
+ // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
+ // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
+ // instead use the search domain list as the sole authority for what domains to search and in what order
+ // (and the domain from the "domain" field will also appear somewhere in that list).
+ // Also, all search domains get added to the search list for resolver[0], so the domains and/or
+ // search lists for other resolvers in the list need to be ignored.
+ if (config->resolver[0]->n_search == 0) mDNS_AddSearchDomain_CString(config->resolver[0]->domain);
+ else for (i = 0; i < config->resolver[0]->n_search; i++) mDNS_AddSearchDomain_CString(config->resolver[0]->search[i]);
}
+ dns_configuration_free(config);
+ setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
+ setsearch = mDNSfalse;
}
}
- }
-
-mDNSlocal void MarkSearchListElem(const char *d)
- {
- SearchListElem *new, *ptr;
- domainname domain;
-
- if (!MakeDomainNameFromDNSNameString(&domain, d))
- { LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d); return; }
-
- if (SameDomainName(&domain, &localdomain) || SameDomainName(&domain, &LocalReverseMapomain))
- { debugf("MarkSearchListElem - ignoring local domain %##s", domain.c); return; }
-
- // if domain is in list, mark as pre-existent (0)
- for (ptr = SearchList; ptr; ptr = ptr->next)
- if (SameDomainName(&ptr->domain, &domain))
- {
- if (ptr->flag != 1) ptr->flag = 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
- break;
- }
-
- // if domain not in list, add to list, mark as add (1)
- if (!ptr)
- {
- new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
- if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
- bzero(new, sizeof(SearchListElem));
- AssignDomainName(&new->domain, &domain);
- new->flag = 1; // add
- new->next = SearchList;
- SearchList = new;
- }
- }
-
-// Get the search domains via OS X resolver routines. Returns mStatus_UnsupporterErr if compiled or run on 10.3 systems
-mDNSlocal mStatus GetSearchDomains(void)
- {
- void *v;
- mStatus err = GetDNSConfig(&v);
-
-#if !MDNS_NO_DNSINFO
- if (!err && v)
- {
- int i;
- dns_config_t *config = v;
- if (!config->n_resolver) return err;
- dns_resolver_t *resolv = config->resolver[0]; // use the first slot for search domains
-
- for (i = 0; i < resolv->n_search; i++) MarkSearchListElem(resolv->search[i]);
- if (resolv->domain) MarkSearchListElem(resolv->domain);
- dns_configuration_free(config);
- }
-#endif
-
- return err;
- }
-
-// Get search domains from dynamic store - used as a fallback mechanism on 10.3 systems, if GetSearchDomains (above) fails.
-mDNSlocal void GetDSSearchDomains(CFDictionaryRef dict)
- {
- char buf[MAX_ESCAPED_DOMAIN_NAME];
- int i, count;
-
- CFStringRef s;
+#endif // MDNS_NO_DNSINFO
- // get all the domains from "Search Domains" field of sharing prefs
- if (dict)
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
+ if (store)
{
- CFArrayRef searchdomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
- if (searchdomains)
+ CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
+ if (dict)
{
- count = CFArrayGetCount(searchdomains);
- for (i = 0; i < count; i++)
+ if (fqdn)
{
- s = CFArrayGetValueAtIndex(searchdomains, i);
- if (!s) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; }
- if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
+ CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
+ if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
{
- LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
- continue;
+ // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
+ CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
+ if (fqdnDict && DDNSSettingEnabled(fqdnDict))
+ {
+ CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
+ if (name)
+ {
+ if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+ !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
+ LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
+ else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
+ }
+ }
}
- MarkSearchListElem(buf);
}
- }
-
- // get DHCP domain field
- CFStringRef dname = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
- if (dname)
- {
- if (CFStringGetCString(dname, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
- MarkSearchListElem(buf);
- else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
- }
- }
- }
-mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
- {
- struct ifaddrs *ifa = NULL;
- SearchListElem *ptr, *prev, *freeSLPtr;
- ARListElem *arList;
- mStatus err;
-
- if (DomainDiscoveryDisabled) return mStatus_NoError;
-
- // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
- for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
-
- // Get search domains from resolver library (available in OS X 10.4 and later), reverting to dynamic store on 10.3 systems
- if (GetSearchDomains() == mStatus_UnsupportedErr) GetDSSearchDomains(dict);
-
- // Construct reverse-map search domains
- ifa = myGetIfAddrs(1);
- while (ifa)
- {
- mDNSAddr addr;
- if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
- {
- mDNSAddr netmask;
- char buffer[256];
- if (!SetupAddr(&netmask, ifa->ifa_netmask))
- {
- sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
- addr.ip.v4.b[2] & netmask.ip.v4.b[2],
- addr.ip.v4.b[1] & netmask.ip.v4.b[1],
- addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
- MarkSearchListElem(buffer);
- }
- }
- ifa = ifa->ifa_next;
- }
-
- // delete elems marked for removal, do queries for elems marked add
- prev = NULL;
- ptr = SearchList;
- while (ptr)
- {
- if (ptr->flag == -1) // remove
- {
- mDNS_StopQuery(m, &ptr->BrowseQ);
- mDNS_StopQuery(m, &ptr->RegisterQ);
- mDNS_StopQuery(m, &ptr->DefBrowseQ);
- mDNS_StopQuery(m, &ptr->DefRegisterQ);
- mDNS_StopQuery(m, &ptr->LegacyBrowseQ);
-
- // deregister records generated from answers to the query
- arList = ptr->AuthRecs;
- ptr->AuthRecs = NULL;
- while (arList)
+ if (RegDomains)
{
- AuthRecord *dereg = &arList->ar;
- arList = arList->next;
- debugf("Deregistering PTR %##s -> %##s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c);
- err = mDNS_Deregister(m, dereg);
- if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
+ CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
+ if (regArray && CFArrayGetCount(regArray) > 0)
+ {
+ CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
+ if (regDict && DDNSSettingEnabled(regDict))
+ {
+ CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
+ if (name)
+ {
+ if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+ !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
+ LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
+ else
+ {
+ debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
+ AppendDNameListElem(&RegDomains, 0, &d);
+ }
+ }
+ }
+ }
}
-
- // remove elem from list, delete
- if (prev) prev->next = ptr->next;
- else SearchList = ptr->next;
- freeSLPtr = ptr;
- ptr = ptr->next;
- freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr);
- continue;
- }
-
- if (ptr->flag == 1) // add
- {
- mStatus err1, err2, err3, err4, err5;
- err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- if (err1 || err2 || err3 || err4 || err5)
- LogMsg("GetDomains for domain %##s returned error(s):\n"
- "%d (mDNS_DomainTypeBrowse)\n"
- "%d (mDNS_DomainTypeBrowseDefault)\n"
- "%d (mDNS_DomainTypeRegistration)\n"
- "%d (mDNS_DomainTypeRegistrationDefault)"
- "%d (mDNS_DomainTypeBrowseLegacy)\n",
- ptr->domain.c, err1, err2, err3, err4, err5);
- ptr->flag = 0;
- }
-
- if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
-
- prev = ptr;
- ptr = ptr->next;
- }
-
- return mStatus_NoError;
- }
-
-//!!!KRS here is where we will give success/failure notification to the UI
-mDNSlocal void SCPrefsDynDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
- {
- (void)m; // unused
- debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
- SetDDNSNameStatus(rr->resrec.name, result);
- }
-mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain)
- {
- OSStatus err = 0;
- char dstring[MAX_ESCAPED_DOMAIN_NAME];
- mDNSu32 secretlen;
- void *secret = NULL;
- domainname *d, canon;
- int i, dlen;
- mDNSu32 type = 'ddns';
- mDNSu32 typelen = sizeof(type);
- char *failedfn = "(none)";
- SecKeychainAttributeList *attrList = NULL;
- SecKeychainItemRef itemRef = NULL;
-
- err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
- if (err) { failedfn = "SecKeychainSetPreferenceDomain"; goto cleanup; }
-
- // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
- ConvertDomainNameToCString(domain, dstring);
- dlen = strlen(dstring);
- for (i = 0; i < dlen; i++) dstring[i] = tolower(dstring[i]); // canonicalize -> lower case
- MakeDomainNameFromDNSNameString(&canon, dstring);
- d = &canon;
-
- // find longest-match key, excluding last label (e.g. excluding ".com")
- while (d->c[0] && *(d->c + d->c[0] + 1))
- {
- if (!ConvertDomainNameToCString(d, dstring)) { LogMsg("SetSecretForDomain: bad domain %##s", d->c); return; }
- dlen = strlen(dstring);
- if (dstring[dlen-1] == '.') { dstring[dlen-1] = '\0'; dlen--; } // chop trailing dot
- SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(dstring), dstring },
- { kSecTypeItemAttr, typelen, (UInt32 *)&type } };
- SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
- SecKeychainSearchRef searchRef;
-
- err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef);
- if (err) { failedfn = "SecKeychainSearchCreateFromAttributes"; goto cleanup; }
-
- err = SecKeychainSearchCopyNext(searchRef, &itemRef);
- if (!err)
- {
- mDNSu32 tags[1];
- SecKeychainAttributeInfo attrInfo;
- mDNSu32 i;
- char keybuf[MAX_ESCAPED_DOMAIN_NAME+1];
- domainname keyname;
-
- tags[0] = kSecAccountItemAttr;
- attrInfo.count = 1;
- attrInfo.tag = tags;
- attrInfo.format = NULL;
-
- err = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, &secretlen, &secret);
- if (err || !attrList) { failedfn = "SecKeychainItemCopyAttributesAndData"; goto cleanup; }
- if (!secretlen || !secret) { LogMsg("SetSecretForDomain - bad shared secret"); return; }
- if (((char *)secret)[secretlen-1]) { LogMsg("SetSecretForDomain - Shared secret not NULL-terminated"); goto cleanup; }
-
- for (i = 0; i < attrList->count; i++)
+ if (BrowseDomains)
{
- SecKeychainAttribute attr = attrList->attr[i];
- if (attr.tag == kSecAccountItemAttr)
+ CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
+ if (browseArray)
{
- if (!attr.length || attr.length > MAX_ESCAPED_DOMAIN_NAME) { LogMsg("SetSecretForDomain - Bad key length %d", attr.length); goto cleanup; }
- memcpy(keybuf, attr.data, attr.length);
- keybuf[attr.length] = 0;
- if (!MakeDomainNameFromDNSNameString(&keyname, keybuf)) { LogMsg("SetSecretForDomain - bad key %s", keybuf); goto cleanup; }
- debugf("Setting shared secret for zone %s with key %##s", dstring, keyname.c);
- mDNS_SetSecretForZone(m, d, &keyname, secret);
- break;
+ for (i = 0; i < CFArrayGetCount(browseArray); i++)
+ {
+ CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
+ if (browseDict && DDNSSettingEnabled(browseDict))
+ {
+ CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
+ if (name)
+ {
+ if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+ !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
+ LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
+ else
+ {
+ debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
+ AppendDNameListElem(&BrowseDomains, 0, &d);
+ }
+ }
+ }
+ }
}
}
- if (i == attrList->count) LogMsg("SetSecretForDomain - no key name set");
- goto cleanup;
+ CFRelease(dict);
}
- else if (err == errSecItemNotFound) d = (domainname *)(d->c + d->c[0] + 1);
- else { failedfn = "SecKeychainSearchCopyNext"; goto cleanup; }
- }
-
- cleanup:
- if (err && err != errSecItemNotFound) LogMsg("Error: SetSecretForDomain - %s failed with error code %d", failedfn, err);
- if (attrList) SecKeychainItemFreeAttributesAndData(attrList, secret);
- if (itemRef) CFRelease(itemRef);
- }
-mDNSlocal void SetSCPrefsBrowseDomainsFromCFArray(mDNS *m, CFArrayRef browseDomains, mDNSBool add)
- {
- if (browseDomains)
- {
- CFIndex count = CFArrayGetCount(browseDomains);
- CFDictionaryRef browseDict;
- char buf[MAX_ESCAPED_DOMAIN_NAME];
- int i;
-
- for (i = 0; i < count; i++)
+ if (RegDomains)
{
- browseDict = (CFDictionaryRef)CFArrayGetValueAtIndex(browseDomains, i);
- if (browseDict && DDNSSettingEnabled(browseDict))
+ CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
+ if (btmm)
{
- CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
- if (name)
+ CFIndex size = CFDictionaryGetCount(btmm);
+ const void *key[size];
+ const void *val[size];
+ CFDictionaryGetKeysAndValues(btmm, key, val);
+ for (i = 0; i < size; i++)
{
- domainname BrowseDomain;
- if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || !MakeDomainNameFromDNSNameString(&BrowseDomain, buf) || !BrowseDomain.c[0])
- LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf[0] ? buf : "(unknown)");
- else SetSCPrefsBrowseDomain(m, &BrowseDomain, add);
+ LogOperation("BackToMyMac %d", i);
+ if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+ LogMsg("Can't read BackToMyMac %d key %s", i, buf);
+ else
+ {
+ mDNSu32 uid = atoi(buf);
+ if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+ LogMsg("Can't read BackToMyMac %d val %s", i, buf);
+ else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
+ {
+ LogOperation("BackToMyMac %d %d %##s", i, uid, d.c);
+ AppendDNameListElem(&RegDomains, uid, &d);
+ }
+ }
}
+ CFRelease(btmm);
}
}
- }
- }
-
-
-mDNSlocal void DynDNSConfigChanged(mDNS *const m)
- {
-#ifdef _LEGACY_NAT_TRAVERSAL_
- static mDNSBool LegacyNATInitialized = mDNSfalse;
-#endif _LEGACY_NAT_TRAVERSAL_
- uDNS_GlobalInfo *u = &m->uDNS_info;
- CFDictionaryRef dict;
- CFStringRef key;
- domainname RegDomain, fqdn;
- CFArrayRef NewBrowseDomains = NULL;
- int nAdditions = 0, nDeletions = 0;
-
- // get fqdn, zone from SCPrefs
- GetUserSpecifiedDDNSConfig(&fqdn, &RegDomain, &NewBrowseDomains);
- ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, fqdn.c[0] ? NULL : &fqdn, RegDomain.c[0] ? NULL : &RegDomain, &DomainDiscoveryDisabled);
- if (!SameDomainName(&RegDomain, &DynDNSRegDomain))
- {
- if (DynDNSRegDomain.c[0])
- {
- RemoveDefRegDomain(&DynDNSRegDomain);
- SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop
- }
- AssignDomainName(&DynDNSRegDomain, &RegDomain);
- if (DynDNSRegDomain.c[0])
+ if (setservers || setsearch)
{
- SetSecretForDomain(m, &DynDNSRegDomain);
- AddDefRegDomain(&DynDNSRegDomain);
- SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNStrue);
+ CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+ if (key)
+ {
+ CFDictionaryRef dict = SCDynamicStoreCopyValue(store, key);
+ if (dict)
+ {
+ if (setservers)
+ {
+ CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
+ if (values)
+ {
+ for (i = 0; i < CFArrayGetCount(values); i++)
+ {
+ CFStringRef s = CFArrayGetValueAtIndex(values, i);
+ char buf[256];
+ mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } };
+ if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) &&
+ inet_aton(buf, (struct in_addr *) &addr.ip.v4))
+ mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
+ }
+ }
+ }
+ if (setsearch)
+ {
+ // Add the manual and/or DHCP-dicovered search domains
+ CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains);
+ if (searchDomains)
+ {
+ for (i = 0; i < CFArrayGetCount(searchDomains); i++)
+ {
+ CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i);
+ if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8))
+ mDNS_AddSearchDomain_CString(buf);
+ }
+ }
+ else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName
+ {
+ // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
+ // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
+ // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
+ // instead use the search domain list as the sole authority for what domains to search and in what order
+ // (and the domain from the "domain" field will also appear somewhere in that list).
+ CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
+ if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8))
+ mDNS_AddSearchDomain_CString(buf);
+ }
+ }
+ CFRelease(dict);
+ }
+ CFRelease(key);
+ }
}
+ CFRelease(store);
}
+ }
- // Add new browse domains to internal list
- if (NewBrowseDomains) SetSCPrefsBrowseDomainsFromCFArray(m, NewBrowseDomains, mDNStrue);
-
- // Remove old browse domains from internal list
- if (DynDNSBrowseDomains)
- {
- SetSCPrefsBrowseDomainsFromCFArray(m, DynDNSBrowseDomains, mDNSfalse);
- CFRelease(DynDNSBrowseDomains);
- }
+mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
+ {
+ SCDynamicStoreRef store = NULL;
+ CFDictionaryRef dict = NULL;
+ CFStringRef key = NULL;
+ CFStringRef string = NULL;
+ int nAdditions = 0;
+ int nDeletions = 0;
+ char buf[256];
+ mStatus err = 0;
- // Replace the old browse domains array with the new array
- DynDNSBrowseDomains = NewBrowseDomains;
-
- if (!SameDomainName(&fqdn, &DynDNSHostname))
- {
- if (DynDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &DynDNSHostname);
- AssignDomainName(&DynDNSHostname, &fqdn);
- if (DynDNSHostname.c[0])
- {
- SetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
- SetDDNSNameStatus(&DynDNSHostname, 1); // Set status to 1 to indicate "in progress"
- mDNS_AddDynDNSHostName(m, &DynDNSHostname, SCPrefsDynDNSCallback, NULL);
- }
- }
+ // get IPv4 settings
- // get DNS settings
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL, NULL);
- if (!store) return;
-
- key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
- if (!key) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
- dict = SCDynamicStoreCopyValue(store, key);
- CFRelease(key);
+ store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
+ require_action(store, exit, err = mStatus_UnknownErr);
- // handle any changes to search domains and DNS server addresses
- if (RegisterSplitDNS(m, &nAdditions, &nDeletions) != mStatus_NoError)
- if (dict) RegisterNameServers(m, dict); // fall back to non-split DNS aware configuration on failure
- RegisterSearchDomains(m, dict); // note that we register name servers *before* search domains
- if (dict) CFRelease(dict);
+ key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
+ require_action(key, exit, err = mStatus_UnknownErr);
- // get IPv4 settings
- key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
- if (!key) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
dict = SCDynamicStoreCopyValue(store, key);
- CFRelease(key);
- CFRelease(store);
- if (!dict) // lost v4
- {
- mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
- if (DynDNSHostname.c[0]) SetDDNSNameStatus(&DynDNSHostname, 1); // Set status to 1 to indicate temporary failure
- return;
- }
+ require_action(dict, exit, err = mStatus_UnknownErr);
// handle router changes
- mDNSAddr r;
- char buf[256];
- r.type = mDNSAddrType_IPv4;
- r.ip.v4.NotAnInteger = 0;
- CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
- if (router)
+
+ r->type = mDNSAddrType_IPv4;
+ r->ip.v4 = zerov4Addr;
+
+ string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
+
+ if (string)
{
struct sockaddr_in saddr;
-
- if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
+
+ if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
LogMsg("Could not convert router to CString");
else
{
saddr.sin_len = sizeof(saddr);
saddr.sin_family = AF_INET;
- saddr.sin_port = 0;
+ saddr.sin_port = 0;
inet_aton(buf, &saddr.sin_addr);
- if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) { debugf("Ignoring router %s (requires PPP connection)", buf); }
- else *(in_addr_t *)&r.ip.v4 = saddr.sin_addr.s_addr;
+
+ if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf);
+ else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
}
}
// handle primary interface changes
// if we gained or lost DNS servers (e.g. logged into VPN) "toggle" primary address so it gets re-registered even if it is unchanged
if (nAdditions || nDeletions) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
- CFStringRef primary = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
- if (primary)
+
+ string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
+
+ if (string)
{
- mDNSAddr v4 = zeroAddr, v6 = zeroAddr;
mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
struct ifaddrs *ifa = myGetIfAddrs(1);
-
- if (!CFStringGetCString(primary, buf, 256, kCFStringEncodingUTF8))
- { LogMsg("Could not convert router to CString"); goto error; }
+
+ *v4 = *v6 = zeroAddr;
+
+ if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
// find primary interface in list
- while (ifa && (!v4.ip.v4.NotAnInteger || !HavePrimaryGlobalv6))
+ while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
{
mDNSAddr tmp6 = zeroAddr;
if (!strcmp(buf, ifa->ifa_name))
- {
- if (ifa->ifa_addr->sa_family == AF_INET) SetupAddr(&v4, ifa->ifa_addr);
- else if (ifa->ifa_addr->sa_family == AF_INET6)
+ {
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ {
+ if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
+ }
+ else if (ifa->ifa_addr->sa_family == AF_INET6)
{
SetupAddr(&tmp6, ifa->ifa_addr);
if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
- { HavePrimaryGlobalv6 = mDNStrue; v6 = tmp6; }
+ { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
}
}
else
{
// We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
- if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6.ip.v6.b[0])
+ if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
{
SetupAddr(&tmp6, ifa->ifa_addr);
- if (tmp6.ip.v6.b[0] >> 5 == 1) v6 = tmp6;
+ if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
}
}
ifa = ifa->ifa_next;
// Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
// V4 to communicate w/ our DNS server
-
- if (v4.ip.v4.b[0] == 169 && v4.ip.v4.b[1] == 254) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL); // primary IP is link-local
+ }
+
+ exit:
+ if (dict) CFRelease(dict);
+ if (key) CFRelease(key);
+ if (store) CFRelease(store);
+ return err;
+ }
+
+mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
+ {
+ LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
+ char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
+ ConvertDomainNameToCString(dname, uname);
+
+ char *p = uname;
+ while (*p)
+ {
+ *p = tolower(*p);
+ if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
+ p++;
+ }
+
+ // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
+ // That single entity is a CFDictionary with name "HostNames".
+ // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
+ // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
+ // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
+ // The CFDictionary for each FQDN holds (at present) a single name/value pair,
+ // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
+
+ const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
+ const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
+ const CFStringRef StatusKeys[1] = { CFSTR("Status") };
+ if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
+ else
+ {
+ const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
+ if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status);
else
{
- if (v4.ip.v4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger ||
- memcmp(v6.ip.v6.b, u->AdvertisedV6.ip.v6.b, 16) ||
- r.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger)
+ const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) };
+ if (HostVals[0])
{
-#ifdef _LEGACY_NAT_TRAVERSAL_
- if (LegacyNATInitialized) { LegacyNATDestroy(); LegacyNATInitialized = mDNSfalse; }
- if (r.ip.v4.NotAnInteger && IsPrivateV4Addr(&v4))
+ const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) };
+ if (StateVals[0])
{
- mStatus err = LegacyNATInit();
- if (err) LogMsg("ERROR: LegacyNATInit");
- else LegacyNATInitialized = mDNStrue;
- }
-#endif _LEGACY_NAT_TRAVERSAL_
- mDNS_SetPrimaryInterfaceInfo(m, &v4, v6.ip.v6.b[0] ? &v6 : NULL, r.ip.v4.NotAnInteger ? &r : NULL);
+ CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL);
+ if (StateDict)
+ {
+ mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, StateDict);
+ CFRelease(StateDict);
+ }
+ CFRelease(StateVals[0]);
+ }
+ CFRelease(HostVals[0]);
}
+ CFRelease(StatusVals[0]);
}
+ CFRelease(HostKeys[0]);
}
- error:
- CFRelease(dict);
+ }
+
+// MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
+mDNSlocal void SetDomainSecrets(mDNS *m)
+ {
+#ifdef NO_SECURITYFRAMEWORK
+ (void)m;
+ LogMsg("Note: SetDomainSecrets: no keychain support");
+#else
+ mDNSBool haveAutoTunnels = mDNSfalse;
+
+ LogOperation("SetDomainSecrets");
+
+ // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
+ // In the case where the user simultaneously removes their DDNS host name and the key
+ // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
+ // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
+ // address records behind that we no longer have permission to delete.
+ DomainAuthInfo *ptr;
+ for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+ ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
+
+#if APPLE_OSX_mDNSResponder
+ {
+ // Mark all TunnelClients for deletion
+ ClientTunnel *client;
+ for (client = m->TunnelClients; client; client = client->next)
+ {
+ LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
+ client->markedForDeletion = mDNStrue;
+ }
+ }
+#endif APPLE_OSX_mDNSResponder
+
+ CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
+ CFIndex i;
+ CFDataRef data = NULL;
+ const int itemsPerEntry = 3; // domain name, key name, key value
+ CFArrayRef secrets = NULL;
+ int err = mDNSKeychainGetSecrets(&secrets);
+ if (err || !secrets)
+ LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
+ else
+ {
+ CFIndex ArrayCount = CFArrayGetCount(secrets);
+ // Iterate through the secrets
+ for (i = 0; i < ArrayCount; ++i)
+ {
+ int j;
+ CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
+ if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
+ { LogMsg("SetDomainSecrets: malformed entry"); continue; }
+ for (j = 0; j < CFArrayGetCount(entry); ++j)
+ if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
+ { LogMsg("SetDomainSecrets: malformed entry item"); continue; }
+
+ // Validate that attributes are not too large
+ char dstring[MAX_ESCAPED_DOMAIN_NAME];
+ char keynamebuf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
+ // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
+ data = CFArrayGetValueAtIndex(entry, 0);
+ if (CFDataGetLength(data) >= (int)sizeof(dstring))
+ { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
+ CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)dstring);
+ dstring[CFDataGetLength(data)] = '\0';
+ data = CFArrayGetValueAtIndex(entry, 1);
+ if (CFDataGetLength(data) >= (int)sizeof(keynamebuf))
+ { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
+ CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)keynamebuf);
+ keynamebuf[CFDataGetLength(data)] = '\0';
+
+ domainname domain;
+ if (!MakeDomainNameFromDNSNameString(&domain, dstring)) { LogMsg("SetDomainSecrets: bad key domain %s", dstring); continue; }
+
+ // Get DNS key name
+ domainname keyname;
+ if (!MakeDomainNameFromDNSNameString(&keyname, keynamebuf)) { LogMsg("SetDomainSecrets: bad key name %s", keynamebuf); continue; }
+
+ // Get DNS key data
+ char keystring[1024];
+ data = CFArrayGetValueAtIndex(entry, 2);
+ if (CFDataGetLength(data) >= (int)sizeof(keystring))
+ { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data)); continue; }
+ CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)keystring);
+ keystring[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
+
+ DomainAuthInfo *FoundInList;
+ for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+ if (SameDomainName(&FoundInList->domain, &domain)) break;
+
+#if APPLE_OSX_mDNSResponder
+ if (FoundInList)
+ {
+ // If any client tunnel destination is in this domain, set deletion flag to false
+ ClientTunnel *client;
+ for (client = m->TunnelClients; client; client = client->next)
+ if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
+ {
+ LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
+ client->markedForDeletion = mDNSfalse;
+ // If the key has changed, reconfigure the tunnel
+ if (strncmp(keystring, client->b64keydata, sizeof(client->b64keydata)))
+ {
+ mDNSBool queryNotInProgress = client->q.ThisQInterval < 0;
+ LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client->dstname.c, queryNotInProgress ? "reconfiguring" : "query in progress");
+ if (queryNotInProgress) AutoTunnelSetKeys(client, mDNSfalse);
+ mDNS_snprintf(client->b64keydata, sizeof(client->b64keydata), "%s", keystring);
+ if (queryNotInProgress) AutoTunnelSetKeys(client, mDNStrue);
+ }
+ }
+ }
+
+ mDNSBool keyChanged = FoundInList && FoundInList->AutoTunnel ? strncmp(keystring, FoundInList->b64keydata, sizeof(FoundInList->b64keydata)) : mDNSfalse;
+
+#endif APPLE_OSX_mDNSResponder
+
+ // Uncomment the line below to view the keys as they're read out of the system keychain
+ // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
+ //LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, keystring);
+
+ // If didn't find desired domain in the list, make a new entry
+ ptr = FoundInList;
+ if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
+ if (!FoundInList)
+ {
+ ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
+ if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
+ }
+
+ LogOperation("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
+ if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, keystring, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr)
+ {
+ if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
+ continue;
+ }
+
+#if APPLE_OSX_mDNSResponder
+ if (keyChanged && AnonymousRacoonConfig)
+ {
+ LogOperation("SetDomainSecrets: secret changed for %##s", &domain);
+ (void)mDNSConfigureServer(kmDNSUp, keystring);
+ }
+#endif APPLE_OSX_mDNSResponder
+
+ CFStringRef cfs = CFStringCreateWithCString(NULL, dstring, kCFStringEncodingUTF8);
+ if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
+ }
+ CFRelease(secrets);
+ }
+ mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, sa);
+ CFRelease(sa);
+
+ #if APPLE_OSX_mDNSResponder
+ {
+ // clean up ClientTunnels
+ ClientTunnel **ptr = &m->TunnelClients;
+ while (*ptr)
+ {
+ if ((*ptr)->markedForDeletion)
+ {
+ ClientTunnel *cur = *ptr;
+ LogOperation("SetDomainSecrets: removing client %##s from list", cur->dstname.c);
+ if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
+ AutoTunnelSetKeys(cur, mDNSfalse);
+ *ptr = cur->next;
+ freeL("ClientTunnel", cur);
+ }
+ else
+ ptr = &(*ptr)->next;
+ }
+
+ DomainAuthInfo *info = m->AuthInfoList;
+ while (info)
+ {
+ if (info->AutoTunnel && info->deltime && info->AutoTunnelNAT.clientContext)
+ {
+ // stop the NAT operation
+ mDNS_StopNATOperation_internal(m, &info->AutoTunnelNAT);
+ if (info->AutoTunnelHostRecord.namestorage.c[0] && info->AutoTunnelNAT.clientCallback)
+ {
+ // reset port and let the AutoTunnelNATCallback handle cleanup
+ info->AutoTunnelNAT.ExternalAddress = m->ExternalAddress;
+ info->AutoTunnelNAT.ExternalPort = zeroIPPort;
+ info->AutoTunnelNAT.Lifetime = 0;
+ info->AutoTunnelNAT.Result = mStatus_NoError;
+ mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
+ info->AutoTunnelNAT.clientCallback(m, &info->AutoTunnelNAT);
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
+ }
+ info->AutoTunnelNAT.clientContext = mDNSNULL;
+ }
+ info = info->next;
+ }
+
+ if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive)
+ {
+ // remove interface if no autotunnel servers and no more client tunnels
+ LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN");
+ m->AutoTunnelHostAddrActive = mDNSfalse;
+ (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
+ memset(m->AutoTunnelHostAddr.b, 0, sizeof(m->AutoTunnelHostAddr.b));
+ }
+
+ if (!haveAutoTunnels && AnonymousRacoonConfig)
+ {
+ LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false");
+ AnonymousRacoonConfig = mDNSfalse;
+ (void)mDNSConfigureServer(kmDNSDown, "");
+ }
+
+ if (m->AutoTunnelHostAddr.b[0])
+ if (TunnelClients(m) || TunnelServers(m))
+ SetupLocalAutoTunnelInterface_internal(m);
+ }
+ #endif APPLE_OSX_mDNSResponder
+
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+
+mDNSlocal void SetLocalDomains(void)
+ {
+ CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
+
+ CFArrayAppendValue(sa, CFSTR("local"));
+ CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
+ CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
+ CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
+ CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
+ CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
+
+ mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, sa);
+ CFRelease(sa);
}
mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
- {
- LogOperation("*** Network Configuration Change ***");
+ {
+ LogOperation("*** Network Configuration Change *** (%d)%s",
+ m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
+ m->p->NetworkChanged ? "": " (no scheduled configuration change)");
m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
mDNSs32 utc = mDNSPlatformUTC();
MarkAllInterfacesInactive(m, utc);
UpdateInterfaceList(m, utc);
int nDeletions = ClearInactiveInterfaces(m, utc);
int nAdditions = SetupActiveInterfaces(m, utc);
- DynDNSConfigChanged(m); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs
+
+ #if APPLE_OSX_mDNSResponder
+ {
+ if (m->AutoTunnelHostAddr.b[0])
+ {
+ mDNS_Lock(m);
+ if (TunnelClients(m) || TunnelServers(m))
+ SetupLocalAutoTunnelInterface_internal(m);
+ mDNS_Unlock(m);
+ }
+
+ // Scan to find client tunnels whose questions have completed,
+ // but whose local inner/outer addresses have changed since the tunnel was set up
+ ClientTunnel *p;
+ for (p = m->TunnelClients; p; p = p->next)
+ if (p->q.ThisQInterval < 0)
+ {
+ mDNSAddr tmpSrc = zeroAddr;
+ mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
+ tmpDst.ip.v4 = p->rmt_outer;
+ FindSourceAddrForIP(&tmpDst, &tmpSrc);
+ if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
+ !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
+ {
+ AutoTunnelSetKeys(p, mDNSfalse);
+ p->loc_inner = m->AutoTunnelHostAddr;
+ p->loc_outer = tmpSrc.ip.v4;
+ AutoTunnelSetKeys(p, mDNStrue);
+ }
+ }
+ }
+ #endif APPLE_OSX_mDNSResponder
+
+ uDNS_SetupDNSConfig(m); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs
if (nDeletions || nAdditions) mDNS_UpdateLLQs(m); // so that LLQs are restarted against the up to date name servers
-
+
if (m->MainCallback)
m->MainCallback(m, mStatus_ConfigChanged);
}
(void)store; // Parameter not used
(void)changedKeys; // Parameter not used
mDNS *const m = (mDNS *const)context;
+ KQueueLock(m);
mDNS_Lock(m);
- mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
+ mDNSs32 delay = mDNSPlatformOneSecond; // Start off assuming a one-second delay
- int c = CFArrayGetCount(changedKeys); // Count changes
+ int c = CFArrayGetCount(changedKeys); // Count changes
CFRange range = { 0, c };
- CFStringRef k1 = SCDynamicStoreKeyCreateComputerName(NULL);
- CFStringRef k2 = SCDynamicStoreKeyCreateHostNames(NULL);
- if (k1 && k2)
- {
- int c1 = (CFArrayContainsValue(changedKeys, range, k1) != 0); // See if ComputerName changed
- int c2 = (CFArrayContainsValue(changedKeys, range, k2) != 0); // See if Local Hostname changed
- int c3 = (CFArrayContainsValue(changedKeys, range, CFSTR("Setup:/Network/DynamicDNS")) != 0);
- if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
- }
- if (k1) CFRelease(k1);
- if (k2) CFRelease(k2);
+ int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
+ int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
+ int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
+ if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/20; // If these were the only changes, shorten delay
- LogOperation("*** NetworkChanged *** %d change%s, delay %d", c, c>1?"s":"", delay);
+#if LogAllOperations
+ int i;
+ for (i=0; i<c; i++)
+ {
+ char buf[256];
+ if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+ LogOperation("*** NetworkChanged SC key: %s", buf);
+ }
+ LogOperation("*** NetworkChanged *** %d change%s %s%s%sdelay %d",
+ c, c>1?"s":"",
+ c1 ? "(Local Hostname) " : "",
+ c2 ? "(Computer Name) " : "",
+ c3 ? "(DynamicDNS) " : "",
+ delay);
+#endif
if (!m->p->NetworkChanged ||
m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
-
+
if (!m->SuppressSending ||
m->SuppressSending - m->p->NetworkChanged < 0)
m->SuppressSending = m->p->NetworkChanged;
+
mDNS_Unlock(m);
+ KQueueUnlock(m, "NetworkChanged");
}
mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
mStatus err = -1;
SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
- CFStringRef key1 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
- CFStringRef key2 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
- CFStringRef key3 = SCDynamicStoreKeyCreateComputerName(NULL);
- CFStringRef key4 = SCDynamicStoreKeyCreateHostNames(NULL);
- CFStringRef key5 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+ CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
-
- CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
- if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error;
-
- CFArrayAppendValue(keys, key1);
- CFArrayAppendValue(keys, key2);
- CFArrayAppendValue(keys, key3);
- CFArrayAppendValue(keys, key4);
- CFArrayAppendValue(keys, key5);
- CFArrayAppendValue(keys, CFSTR("Setup:/Network/DynamicDNS"));
+ if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
+
+ CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
+ CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
+ CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
+ CFArrayAppendValue(keys, NetworkChangedKey_Computername);
+ CFArrayAppendValue(keys, NetworkChangedKey_DNS);
+ CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
+ CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
CFArrayAppendValue(patterns, pattern1);
CFArrayAppendValue(patterns, pattern2);
CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
err = 0;
goto exit;
-error:
+ error:
if (store) CFRelease(store);
-exit:
- if (key1) CFRelease(key1);
- if (key2) CFRelease(key2);
- if (key3) CFRelease(key3);
- if (key4) CFRelease(key4);
- if (key5) CFRelease(key5);
- if (pattern1) CFRelease(pattern1);
+ exit:
+ if (patterns) CFRelease(patterns);
if (pattern2) CFRelease(pattern2);
+ if (pattern1) CFRelease(pattern1);
if (keys) CFRelease(keys);
- if (patterns) CFRelease(patterns);
-
+
return(err);
}
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
+ {
+ LogOperation("*** Keychain Changed ***");
+ mDNS *const m = (mDNS *const)context;
+ SecKeychainRef skc;
+ OSStatus err = SecKeychainCopyDefault(&skc);
+ if (!err)
+ {
+ if (info->keychain == skc)
+ {
+ // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
+ mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
+ if (!relevant)
+ {
+ UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
+ SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
+ SecKeychainAttributeList *a = NULL;
+ err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
+ if (!err)
+ {
+ relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
+ (a->attr[1].length >= 4 && (!strncasecmp(a->attr[1].data, "dns:", 4))));
+ SecKeychainItemFreeAttributesAndData(a, NULL);
+ }
+ }
+ if (relevant)
+ {
+ LogMsg("*** Keychain Changed *** KeychainEvent=%d %s",
+ keychainEvent,
+ keychainEvent == kSecAddEvent ? "kSecAddEvent" :
+ keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
+ keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
+ KQueueLock(m);
+ mDNS_Lock(m);
+ SetDomainSecrets(m);
+ mDNS_Unlock(m);
+ KQueueUnlock(m, "KeychainChanged");
+ }
+ }
+ CFRelease(skc);
+ }
+
+ return 0;
+ }
+#endif
+
+#ifndef NO_IOPOWER
mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
{
mDNS *const m = (mDNS *const)refcon;
+ KQueueLock(m);
(void)service; // Parameter not used
switch(messageType)
{
default: LogOperation("PowerChanged unknown message %X", messageType); break;
}
IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
+ KQueueUnlock(m, "Sleep/Wake");
}
+#endif /* NO_IOPOWER */
-mDNSlocal mStatus WatchForPowerChanges(mDNS *const m)
- {
- IONotificationPortRef thePortRef;
- m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier);
- if (m->p->PowerConnection)
- {
- m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
- return(mStatus_NoError);
- }
- return(-1);
- }
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Initialization & Teardown
+#endif
CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
{
int major = 0, minor = 0;
- char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?";
+ char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
CFDictionaryRef vers = _CFCopySystemVersionDictionary();
if (vers)
{
sscanf(buildver, "%d%c%d", &major, &letter, &minor);
CFRelease(vers);
}
+ if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); }
if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString);
return(major);
}
return(err == 0);
}
-// Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
-mDNSlocal void FoundLegacyBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
- {
- DNameListElem *ptr, *prev, *new;
- (void)m; // unused;
- (void)question; // unused
-
- LogMsg("%s browse domain %##s", AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
-
- if (AddRecord)
- {
- new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem));
- if (!new) { LogMsg("ERROR: malloc"); return; }
- AssignDomainName(&new->name, &answer->rdata->u.name);
- new->next = DefBrowseList;
- DefBrowseList = new;
- DefaultBrowseDomainChanged(&new->name, mDNStrue);
- udsserver_default_browse_domain_changed(&new->name, mDNStrue);
- return;
- }
- else
- {
- ptr = DefBrowseList;
- prev = NULL;
- while (ptr)
- {
- if (SameDomainName(&ptr->name, &answer->rdata->u.name))
- {
- DefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
- udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
- if (prev) prev->next = ptr->next;
- else DefBrowseList = ptr->next;
- freeL("FoundLegacyBrowseDomain", ptr);
- return;
- }
- prev = ptr;
- ptr = ptr->next;
- }
- LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %##s not in list", answer->rdata->u.name.c);
- }
- }
-
-mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
- {
- // allocate/register legacy and non-legacy _browse PTR record
- ARListElem *browse = mallocL("ARListElem", sizeof(*browse));
- mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, browse);
- MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]);
- AppendDNSNameString (browse->ar.resrec.name, "local");
- AssignDomainName(&browse->ar.resrec.rdata->u.name, d);
- mStatus err = mDNS_Register(m, &browse->ar);
- if (err)
- {
- LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
- freeL("ARListElem", browse);
- }
- else
- {
- browse->next = SCPrefBrowseDomains;
- SCPrefBrowseDomains = browse;
- }
- }
-
-mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
- {
- ARListElem *remove, **ptr = &SCPrefBrowseDomains;
- domainname lhs; // left-hand side of PTR, for comparison
-
- MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
- AppendDNSNameString (&lhs, "local");
-
- while (*ptr)
- {
- if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
- {
- remove = *ptr;
- *ptr = (*ptr)->next;
- mDNS_Deregister(m, &remove->ar);
- return;
- }
- else ptr = &(*ptr)->next;
- }
- }
-
-// Add or remove a user-specified domain to the list of empty-string browse domains
-// Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
-mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
- {
- debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
-
- if (add)
- {
- RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
- RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
- }
- else
- {
- DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
- DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
- }
- }
-
// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
// 1) query for b._dns-sd._udp.local on LocalOnly interface
// (.local manually generated via explicit callback)
// 6) client calls to enumerate domains now go over LocalOnly interface
// (!!!KRS may add outgoing interface in addition)
-mDNSlocal mStatus InitDNSConfig(mDNS *const m)
+mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
{
mStatus err;
- static AuthRecord LocalRegPTR;
-
- // start query for domains to be used in default (empty string domain) browses
- err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundLegacyBrowseDomain, NULL);
-
- // provide browse domain "local" automatically
- SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
-
- // register registration domain "local"
- mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, NULL, NULL);
- MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]);
- AppendDNSNameString (LocalRegPTR.resrec.name, "local");
- AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain);
- err = mDNS_Register(m, &LocalRegPTR);
- if (err) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err);
-
- return mStatus_NoError;
- }
-mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
- {
// In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
// If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
int i;
usleep(50000);
}
- mStatus err;
+ m->hostlabel.c[0] = 0;
- m->hostlabel.c[0] = 0;
-
char *HINFO_HWstring = "Macintosh";
char HINFO_HWstring_buffer[256];
int get_model[2] = { CTL_HW, HW_MODEL };
if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
-#ifndef NO_HINFO
mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
if (hlen + slen < 254)
{
m->HIHardware.c[0] = hlen;
m->HISoftware.c[0] = slen;
- mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen);
- mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen);
+ mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
+ mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
}
-#endif /* NO_HINFO */
- m->p->unicastsockets.m = m;
- m->p->unicastsockets.info = NULL;
- m->p->unicastsockets.sktv4 = m->p->unicastsockets.sktv6 = -1;
- m->p->unicastsockets.cfsv4 = m->p->unicastsockets.cfsv6 = NULL;
- m->p->unicastsockets.rlsv4 = m->p->unicastsockets.rlsv6 = NULL;
-
- err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET);
- err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET6);
+ m->p->permanentsockets.m = m;
+ m->p->permanentsockets.sktv4 = m->p->permanentsockets.sktv6 = -1;
+ m->p->permanentsockets.kqsv4.KQcallback = m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
+ m->p->permanentsockets.kqsv4.KQcontext = m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
+ m->p->permanentsockets.kqsv4.KQtask = m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
+
+ err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET);
+#ifndef NO_IPV6
+ err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6);
+#endif
struct sockaddr_in s4;
- struct sockaddr_in6 s6;
socklen_t n4 = sizeof(s4);
- socklen_t n6 = sizeof(s6);
- if (getsockname(m->p->unicastsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
+ if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
else m->UnicastPort4.NotAnInteger = s4.sin_port;
- if (getsockname(m->p->unicastsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
- else m->UnicastPort6.NotAnInteger = s6.sin6_port;
+#ifndef NO_IPV6
+ if (m->p->permanentsockets.sktv6 >= 0)
+ {
+ struct sockaddr_in6 s6;
+ socklen_t n6 = sizeof(s6);
+ if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
+ else m->UnicastPort6.NotAnInteger = s6.sin6_port;
+ }
+#endif
m->p->InterfaceList = mDNSNULL;
m->p->userhostlabel.c[0] = 0;
m->p->usernicelabel.c[0] = 0;
m->p->NotifyUser = 0;
+
+ m->AutoTunnelHostAddr.b[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
+
mDNSs32 utc = mDNSPlatformUTC();
UpdateInterfaceList(m, utc);
SetupActiveInterfaces(m, utc);
+ NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
+ NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
+ NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
+ NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
+ NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+ if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS)
+ { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
+
err = WatchForNetworkChanges(m);
- if (err) return(err);
-
- err = WatchForPowerChanges(m);
- if (err) return err;
+ if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
+
+ // Explicitly ensure that our Keychain operations utilize the system domain.
+#ifndef NO_SECURITYFRAMEWORK
+ SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+#endif
+
+ mDNS_Lock(m);
+ SetDomainSecrets(m);
+ SetLocalDomains();
+ mDNS_Unlock(m);
+
+#ifndef NO_SECURITYFRAMEWORK
+ err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
+ if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
+#endif
- DynDNSRegDomain.c[0] = '\0';
- DynDNSConfigChanged(m); // Get initial DNS configuration
+#ifndef NO_IOPOWER
+ m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
+ if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
+ else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
+#endif /* NO_IOPOWER */
- InitDNSConfig(m);
- return(err);
+ return(mStatus_NoError);
}
mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
{
+#if MDNS_NO_DNSINFO
+ LogMsg("Note: Compiled without Apple-specific Split-DNS support");
+#endif
+
mStatus result = mDNSPlatformInit_setup(m);
-
+
// We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
// have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
{
if (m->p->PowerConnection)
{
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode);
- CFRunLoopSourceInvalidate(m->p->PowerRLS);
- CFRelease(m->p->PowerRLS);
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
+#ifndef NO_IOPOWER
+ // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
+ // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
IODeregisterForSystemPower(&m->p->PowerNotifier);
+ IOServiceClose ( m->p->PowerConnection);
+ IONotificationPortDestroy ( m->p->PowerPortRef);
+#endif /* NO_IOPOWER */
m->p->PowerConnection = 0;
- m->p->PowerNotifier = 0;
- m->p->PowerRLS = NULL;
}
-
+
if (m->p->Store)
{
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
m->p->Store = NULL;
m->p->StoreRLS = NULL;
}
-
+
mDNSs32 utc = mDNSPlatformUTC();
MarkAllInterfacesInactive(m, utc);
ClearInactiveInterfaces(m, utc);
- CloseSocketSet(&m->p->unicastsockets);
+ CloseSocketSet(&m->p->permanentsockets);
+
+ #if APPLE_OSX_mDNSResponder
+ if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0])
+ {
+ m->AutoTunnelHostAddrActive = mDNSfalse;
+ LogMsg("Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
+ (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
+ }
+ #endif // APPLE_OSX_mDNSResponder
}
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Platform Support Layer functions
+#endif
+
mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
{
return(mach_absolute_time());
if (clockdivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
static uint64_t last_mach_absolute_time = 0;
+ //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
uint64_t this_mach_absolute_time = mach_absolute_time();
if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
{
LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
// Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
last_mach_absolute_time = this_mach_absolute_time;
- // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later
+ // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later.
+ // (This bug happens all the time on 10.3, and we know that's not going to be fixed.)
if (mDNSMacOSXSystemBuildNumber(NULL) >= 8)
- NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
+ NotifyOfElusiveBug("mach_absolute_time went backwards!",
+ "This error occurs from time to time, often on newly released hardware, "
+ "and usually the exact cause is different in each instance.\r\r"
+ "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
+ "and assign it to Radar Component “Kernel” Version “X”.");
}
last_mach_absolute_time = this_mach_absolute_time;
// Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
-mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { strcpy((char *)dst, (char *)src); }
-mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src) { return(strlen((char*)src)); }
-mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len) { memcpy(dst, src, len); }
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
-mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); }
+mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
+mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
+mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
+mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
+mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); }
+#if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
+#endif
mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSMacOSX.h,v $
-Revision 1.51 2005/07/04 22:24:36 cheshire
-Export NotifyOfElusiveBug() so other files can call it
-
-Revision 1.50 2005/02/19 00:04:18 cheshire
-Add comments
-
-Revision 1.49 2004/12/17 23:37:47 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.48 2004/12/07 01:31:31 cheshire
-mDNSMacOSXSystemBuildNumber() returns int, not mDNSBool
-
-Revision 1.47 2004/11/30 03:24:03 cheshire
-<rdar://problem/3854544> Defer processing network configuration changes until configuration has stabilized
-
-Revision 1.46 2004/11/03 03:45:16 cheshire
-<rdar://problem/3863627> mDNSResponder does not inform user of Computer Name collisions
-
-Revision 1.45 2004/10/28 00:53:57 cheshire
-Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c;
-Add LogOperation() call to record when we get network change events
-
-Revision 1.44 2004/10/23 01:16:01 cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
-
-Revision 1.43 2004/10/15 23:00:18 ksekar
-<rdar://problem/3799242> Need to update LLQs on location changes
-
-Revision 1.42 2004/10/04 05:56:04 cheshire
-<rdar://problem/3824730> mDNSResponder doesn't respond to certain AirPort changes
-
-Revision 1.41 2004/09/30 00:24:59 ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
-
-Revision 1.40 2004/09/17 01:08:52 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.39 2004/08/18 17:35:41 ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
-
-Revision 1.38 2004/07/13 21:24:25 rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.37 2004/06/04 08:58:30 ksekar
-<rdar://problem/3668624>: Keychain integration for secure dynamic update
-
-Revision 1.36 2004/05/26 17:06:33 cheshire
-<rdar://problem/3668515>: Don't rely on CFSocketInvalidate() to remove RunLoopSource
-
-Revision 1.35 2004/05/18 23:51:26 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.34 2004/05/12 22:03:09 ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms. Changed call to return a copy of the list
-to avoid shared memory issues. Added a routine to free the list.
-
-Revision 1.33 2004/05/12 02:03:25 ksekar
-Non-local domains will only be browsed by default, and show up in
-_browse domain enumeration, if they contain an _browse._dns-sd ptr record.
-
-Revision 1.32 2004/04/21 02:20:47 cheshire
-Rename interface field 'CurrentlyActive' to more descriptive 'Exists'
+Revision 1.72 2007/08/01 16:09:14 cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-Revision 1.31 2004/04/09 17:40:26 cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing TxAndRx field
+Revision 1.71 2007/07/27 23:57:23 cheshire
+Added compile-time structure size checks
-Revision 1.30 2004/01/28 02:30:08 ksekar
-Added default Search Domains to unicast browsing, controlled via
-Networking sharing prefs pane. Stopped sending unicast messages on
-every interface. Fixed unicast resolving via mach-port API.
+Revision 1.70 2007/07/11 02:55:50 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Remove unused DefaultRegDomainChanged/DefaultBrowseDomainChanged
-Revision 1.29 2004/01/27 22:57:48 cheshire
-<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+Revision 1.69 2007/05/08 00:56:17 cheshire
+<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
-Revision 1.28 2004/01/27 20:15:23 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.68 2007/04/24 00:10:15 cheshire
+Increase WatchDogReportingThreshold to 250ms for customer builds
-Revision 1.27 2004/01/24 08:46:26 bradley
-Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs.
+Revision 1.67 2007/04/21 21:47:47 cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
-Revision 1.26 2003/12/08 21:00:46 rpantos
-Changes to support mDNSResponder on Linux.
+Revision 1.66 2007/04/07 01:01:48 cheshire
+<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
-Revision 1.25 2003/11/08 22:18:29 cheshire
-<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+Revision 1.65 2007/03/07 02:50:50 cheshire
+<rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
-Revision 1.24 2003/11/08 22:13:00 cheshire
-Move extern declarations inside '#ifdef __cplusplus extern "C" {' section
+Revision 1.64 2007/03/06 23:29:50 cheshire
+<rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
-Revision 1.23 2003/09/23 16:38:25 cheshire
-When LogAllOperations is false, treat LogOperation() like debugf()
-(i.e. show in debug builds), rather than unconditionally ignoring
+Revision 1.63 2007/02/07 19:32:00 cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-Revision 1.22 2003/09/23 02:12:43 cheshire
-Also include port number in list of services registered via new UDS API
+Revision 1.62 2007/01/05 08:30:49 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.21 2003/08/19 22:20:00 cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
-More minor refinements
+Revision 1.61 2006/08/14 23:24:40 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.20 2003/08/19 05:39:43 cheshire
-<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
+Revision 1.60 2006/07/27 03:24:35 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinement: Declare KQueueEntry parameter "const"
-Revision 1.19 2003/08/19 05:36:45 cheshire
-Add missing "extern" directives
+Revision 1.59 2006/07/27 02:59:25 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
+after releasing BigMutex, in case actions it took have resulted in new work for the
+kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
+add new active interfaces to its list, and consequently schedule queries to be sent).
-Revision 1.18 2003/08/19 03:04:43 cheshire
-<rdar://problem/3376721> Don't use IPv6 on interfaces that have a routable IPv4 address configured
+Revision 1.58 2006/07/22 06:08:29 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
+Further changes
-Revision 1.17 2003/08/12 19:56:25 cheshire
-Update to APSL 2.0
+Revision 1.57 2006/07/22 03:43:26 cheshire
+<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Revision 1.16 2003/08/08 18:36:04 cheshire
-<rdar://problem/3344154> Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug
+Revision 1.56 2006/07/05 23:37:26 cheshire
+Remove unused LegacyNATInit/LegacyNATDestroy declarations
-Revision 1.15 2003/08/05 00:32:28 cheshire
-<rdar://problem/3326712> Time to turn off MACOSX_MDNS_MALLOC_DEBUGGING
+Revision 1.55 2006/06/29 05:33:30 cheshire
+<rdar://problem/4607043> mDNSResponder conditional compilation options
-Revision 1.14 2003/07/20 03:38:51 ksekar
-<rdar://problem/3320722> Completed support for Unix-domain socket based API.
+Revision 1.54 2006/03/19 03:27:49 cheshire
+<rdar://problem/4118624> Suppress "interface flapping" logic for loopback
-Revision 1.13 2003/07/18 00:30:00 cheshire
-<rdar://problem/3268878> Remove mDNSResponder version from packet header and use HINFO record instead
+Revision 1.53 2006/03/19 02:00:09 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-Revision 1.12 2003/07/12 03:15:20 cheshire
-<rdar://problem/3324848> After SCDynamicStore notification, mDNSResponder updates
-m->hostlabel even if user hasn't actually actually changed their dot-local hostname
-
-Revision 1.11 2003/07/02 21:19:51 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.10 2003/06/25 23:42:19 ksekar
-<rdar://problem/3249292>: Feature: New DNS-SD APIs (#7875)
-Reviewed by: Stuart Cheshire
-Added files necessary to implement Unix domain sockets based enhanced
-DNS-SD APIs, and integrated with existing Mach-port based daemon.
-
-Revision 1.9 2003/06/10 01:14:11 cheshire
-<rdar://problem/3286004> New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call
-
-Revision 1.8 2003/05/14 07:08:37 cheshire
-<rdar://problem/3159272> mDNSResponder should be smarter about reconfigurations
-Previously, when there was any network configuration change, mDNSResponder
-would tear down the entire list of active interfaces and start again.
-That was very disruptive, and caused the entire cache to be flushed,
-and caused lots of extra network traffic. Now it only removes interfaces
-that have really gone, and only adds new ones that weren't there before.
-
-Revision 1.7 2003/04/26 02:39:24 cheshire
-Remove extern void LogMsg(const char *format, ...);
-
-Revision 1.6 2003/03/05 21:59:56 cheshire
-<rdar://problem/3189097> Additional debugging code in mDNSResponder
-
-Revision 1.5 2003/03/05 01:50:38 cheshire
-<rdar://problem/3189097> Additional debugging code in mDNSResponder
-
-Revision 1.4 2003/02/21 01:54:10 cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.3 2002/09/21 20:44:51 zarzycki
-Added APSL info
-
-Revision 1.2 2002/09/19 04:20:44 cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.1 2002/09/17 01:04:09 cheshire
-Defines mDNS_PlatformSupport_struct for OS X
+Revision 1.52 2006/01/05 21:41:49 cheshire
+<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
*/
typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX;
+typedef void (*KQueueEventCallback)(int fd, short filter, void *context);
+typedef struct
+ {
+ KQueueEventCallback KQcallback;
+ void *KQcontext;
+ const char const *KQtask; // For debugging messages
+ } KQueueEntry;
+
typedef struct
{
mDNS *m;
- NetworkInterfaceInfoOSX *info;
int sktv4;
- CFSocketRef cfsv4;
- CFRunLoopSourceRef rlsv4;
+ KQueueEntry kqsv4;
int sktv6;
- CFSocketRef cfsv6;
- CFRunLoopSourceRef rlsv6;
- } CFSocketSet;
+ KQueueEntry kqsv6;
+ } KQSocketSet;
struct NetworkInterfaceInfoOSX_struct
{
NetworkInterfaceInfoOSX *next;
mDNSu32 Exists; // 1 = currently exists in getifaddrs list; 0 = doesn't
// 2 = exists, but McastTxRx state changed
+ mDNSs32 AppearanceTime; // Time this interface appeared most recently in getifaddrs list
+ // i.e. the first time an interface is seen, AppearanceTime is set.
+ // If an interface goes away temporarily and then comes back then
+ // AppearanceTime is updated to the time of the most recent appearance.
mDNSs32 LastSeen; // If Exists==0, last time this interface appeared in getifaddrs list
+ mDNSBool Flashing; // Set if interface appeared for less than 60 seconds and then vanished
+ mDNSBool Occulting; // Set if interface vanished for less than 60 seconds and then came back
char *ifa_name; // Memory for this is allocated using malloc
+ unsigned int ifa_flags;
+ struct in_addr ifa_v4addr;
mDNSu32 scope_id; // interface index / IPv6 scope ID
mDNSEthAddr BSSID; // BSSID of 802.11 base station, if applicable
u_short sa_family;
- mDNSBool Multicast;
- CFSocketSet ss;
};
struct mDNS_PlatformSupport_struct
- {
- NetworkInterfaceInfoOSX *InterfaceList;
- CFSocketSet unicastsockets;
- domainlabel userhostlabel; // The hostlabel as it was set in System Preferences the last time we looked
- domainlabel usernicelabel; // The nicelabel as it was set in System Preferences the last time we looked
- mDNSs32 NotifyUser;
- mDNSs32 NetworkChanged;
- SCDynamicStoreRef Store;
- CFRunLoopSourceRef StoreRLS;
- io_connect_t PowerConnection;
- io_object_t PowerNotifier;
- CFRunLoopSourceRef PowerRLS;
- };
-
-extern void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg);
+ {
+ NetworkInterfaceInfoOSX *InterfaceList;
+ KQSocketSet permanentsockets;
+ domainlabel userhostlabel; // The hostlabel as it was set in System Preferences the last time we looked
+ domainlabel usernicelabel; // The nicelabel as it was set in System Preferences the last time we looked
+ mDNSs32 NotifyUser;
+ mDNSs32 HostNameConflict; // Time we experienced conflict on our link-local host name
+ mDNSs32 NetworkChanged;
+ SCDynamicStoreRef Store;
+ CFRunLoopSourceRef StoreRLS;
+ IONotificationPortRef PowerPortRef;
+ io_connect_t PowerConnection;
+ io_object_t PowerNotifier;
+ pthread_mutex_t BigMutex;
+ mDNSs32 BigMutexStartTime;
+ int WakeKQueueLoopFD;
+ };
+
+extern int KQueueFD;
+
+extern void NotifyOfElusiveBug(const char *title, const char *msg); // Both strings are UTF-8 text
extern void mDNSMacOSXNetworkChanged(mDNS *const m);
extern int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
-extern const char mDNSResponderVersionString[];
+extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef);
+
+// When events are processed on the non-kqueue thread (i.e. CFRunLoop notifications like Sleep/Wake,
+// Interface changes, Keychain changes, etc.) they must use KQueueLock/KQueueUnlock to lock out the kqueue thread
+extern void KQueueLock(mDNS *const m);
+extern void KQueueUnlock(mDNS *const m, const char const *task);
+
+// If any event takes more than WatchDogReportingThreshold milliseconds to be processed, we log a warning message
+// General event categories are:
+// o Mach client request initiated / terminated
+// o UDS client request
+// o Handling UDP packets received from the network
+// o Environmental change events:
+// - network interface changes
+// - sleep/wake
+// - keychain changes
+// o Name conflict dialog dismissal
+// o Reception of Unix signal (e.g. SIGINFO)
+// o Idle task processing
+// If we find that we're getting warnings for any of these categories, and it's not evident
+// what's causing the problem, we may need to subdivide some categories into finer-grained
+// sub-categories (e.g. "Idle task processing" covers a pretty broad range of sub-tasks).
+
+#if LogAllOperations
+#define WatchDogReportingThreshold 50
+#else
+#define WatchDogReportingThreshold 250
+#endif
-// Legacy NAT Traversal Support Setup/Teardown
-extern int LegacyNATDestroy(void);
-extern int LegacyNATInit(void);
+struct CompileTimeAssertionChecks_mDNSMacOSX
+ {
+ // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
+ // other overly-large structures instead of having a pointer to them, can inadvertently
+ // cause structure sizes (and therefore memory usage) to balloon unreasonably.
+ char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <= 4100) ? 1 : -1];
+ char sizecheck_mDNS_PlatformSupport [(sizeof(mDNS_PlatformSupport) <= 260) ? 1 : -1];
+ };
-// Allow platform layer to tell daemon when default registration/browse domains
-extern void DefaultRegDomainChanged(const domainname *d, mDNSBool add);
-extern void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add);
-
#ifdef __cplusplus
}
#endif
+++ /dev/null
-/*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- *
- * This file is not normally used.
- * It can be conditionally compiled in by defining RUN_ON_PUMA_WITHOUT_IFADDRS
- * in mDNSMacOSX.c. It is included mainly as sample code for people building
- * for other platforms that (like Puma) lack the getifaddrs() call.
- * NOTE: YOU CANNOT use this code to build an mDNSResponder daemon for Puma
- * that works just like the Jaguar one, because Puma lacks other necessary
- * functionality (like the LibInfo support to receive MIG messages from clients).
-
- Change History (most recent first):
-
-$Log: mDNSMacOSXPuma.c,v $
-Revision 1.5 2004/09/20 23:52:02 cheshire
-CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c
-
-Revision 1.4 2003/08/12 19:56:25 cheshire
-Update to APSL 2.0
-
-Revision 1.3 2003/07/02 21:19:51 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2 2002/09/21 20:44:51 zarzycki
-Added APSL info
-
-Revision 1.1 2002/09/17 01:36:23 cheshire
-Move Puma support to mDNSMacOSXPuma.c
-
- */
-
-#include <sys/ioctl.h>
-#include <sys/sockio.h>
-#define ifaddrs ifa_info
-#ifndef ifa_broadaddr
-#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
-#endif
-#include <sys/cdefs.h>
-
-/* Our own header for the programs that need interface configuration info.
- Include this file, instead of "unp.h". */
-
-#define IFA_NAME 16 /* same as IFNAMSIZ in <net/if.h> */
-#define IFA_HADDR 8 /* allow for 64-bit EUI-64 in future */
-
-struct ifa_info {
- char ifa_name[IFA_NAME]; /* interface name, null terminated */
- u_char ifa_haddr[IFA_HADDR]; /* hardware address */
- u_short ifa_hlen; /* #bytes in hardware address: 0, 6, 8 */
- short ifa_flags; /* IFF_xxx constants from <net/if.h> */
- short ifa_myflags; /* our own IFI_xxx flags */
- struct sockaddr *ifa_addr; /* primary address */
- struct sockaddr *ifa_brdaddr;/* broadcast address */
- struct sockaddr *ifa_dstaddr;/* destination address */
- struct ifa_info *ifa_next; /* next of these structures */
-};
-
-#define IFI_ALIAS 1 /* ifa_addr is an alias */
-
- /* function prototypes */
-struct ifa_info *get_ifa_info(int, int);
-struct ifa_info *Get_ifa_info(int, int);
-void free_ifa_info(struct ifa_info *);
-
-#define HAVE_SOCKADDR_SA_LEN 1
-
-struct ifa_info *
-get_ifa_info(int family, int doaliases)
-{
- struct ifa_info *ifi, *ifihead, **ifipnext;
- int sockfd, len, lastlen, flags, myflags;
- char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
- struct ifconf ifc;
- struct ifreq *ifr, ifrcopy;
- struct sockaddr_in *sinptr;
-
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-
- lastlen = 0;
- len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
- for ( ; ; ) {
- buf = (char *) malloc(len);
- ifc.ifc_len = len;
- ifc.ifc_buf = buf;
- if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
- if (errno != EINVAL || lastlen != 0)
- debugf("ioctl error");
- } else {
- if (ifc.ifc_len == lastlen)
- break; /* success, len has not changed */
- lastlen = ifc.ifc_len;
- }
- len += 10 * sizeof(struct ifreq); /* increment */
- free(buf);
- }
- ifihead = NULL;
- ifipnext = &ifihead;
- lastname[0] = 0;
-/* end get_ifa_info1 */
-
-/* include get_ifa_info2 */
- for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
- ifr = (struct ifreq *) ptr;
-
-#ifdef HAVE_SOCKADDR_SA_LEN
- len = MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
-#else
- switch (ifr->ifr_addr.sa_family) {
-#ifdef IPV6
- case AF_INET6:
- len = sizeof(struct sockaddr_in6);
- break;
-#endif
- case AF_INET:
- default:
- len = sizeof(struct sockaddr);
- break;
- }
-#endif /* HAVE_SOCKADDR_SA_LEN */
- ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
-
- if (ifr->ifr_addr.sa_family != family)
- continue; /* ignore if not desired address family */
-
- myflags = 0;
- if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
- *cptr = 0; /* replace colon will null */
- if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
- if (doaliases == 0)
- continue; /* already processed this interface */
- myflags = IFI_ALIAS;
- }
- memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
-
- ifrcopy = *ifr;
- ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
- flags = ifrcopy.ifr_flags;
- if ((flags & IFF_UP) == 0)
- continue; /* ignore if interface not up */
-
- ifi = (struct ifa_info *) calloc(1, sizeof(struct ifa_info));
- *ifipnext = ifi; /* prev points to this new one */
- ifipnext = &ifi->ifa_next; /* pointer to next one goes here */
-
- ifi->ifa_flags = flags; /* IFF_xxx values */
- ifi->ifa_myflags = myflags; /* IFI_xxx values */
- memcpy(ifi->ifa_name, ifr->ifr_name, IFA_NAME);
- ifi->ifa_name[IFA_NAME-1] = '\0';
-/* end get_ifa_info2 */
-/* include get_ifa_info3 */
- switch (ifr->ifr_addr.sa_family) {
- case AF_INET:
- sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
- if (ifi->ifa_addr == NULL) {
- ifi->ifa_addr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
- memcpy(ifi->ifa_addr, sinptr, sizeof(struct sockaddr_in));
-
-#ifdef SIOCGIFBRDADDR
- if (flags & IFF_BROADCAST) {
- ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
- sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
- ifi->ifa_brdaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
- memcpy(ifi->ifa_brdaddr, sinptr, sizeof(struct sockaddr_in));
- }
-#endif
-
-#ifdef SIOCGIFDSTADDR
- if (flags & IFF_POINTOPOINT) {
- ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
- sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
- ifi->ifa_dstaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in));
- memcpy(ifi->ifa_dstaddr, sinptr, sizeof(struct sockaddr_in));
- }
-#endif
- }
- break;
-
- default:
- break;
- }
- }
- free(buf);
- return(ifihead); /* pointer to first structure in linked list */
-}
-/* end get_ifa_info3 */
-
-/* include free_ifa_info */
-mDNSlocal void freeifaddrs(struct ifa_info *ifihead)
-{
- struct ifa_info *ifi, *ifinext;
-
- for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
- if (ifi->ifa_addr != NULL)
- free(ifi->ifa_addr);
- if (ifi->ifa_brdaddr != NULL)
- free(ifi->ifa_brdaddr);
- if (ifi->ifa_dstaddr != NULL)
- free(ifi->ifa_dstaddr);
- ifinext = ifi->ifa_next; /* can't fetch ifa_next after free() */
- free(ifi); /* the ifa_info{} itself */
- }
-}
-/* end free_ifa_info */
-
-struct ifa_info *
-Get_ifa_info(int family, int doaliases)
-{
- struct ifa_info *ifi;
-
- if ( (ifi = get_ifa_info(family, doaliases)) == NULL)
- debugf("get_ifa_info error");
- return(ifi);
-}
-
-mDNSlocal int getifaddrs(struct ifa_info **ifalist)
- {
- *ifalist = get_ifa_info(PF_INET, false);
- if( ifalist == nil )
- return -1;
- else
- return(0);
- }
-"The name of your computer" = "The name of your computer";
-"This computer’s local hostname" = "This computer’s local hostname";
-"is already in use on this network." = "is already in use on this network.";
+"The name of your computer " = "The name of your computer ";
+"This computer’s local hostname " = "This computer’s local hostname ";
+"“" = "“";
+"”" = "”";
+" is already in use on this network. " = " is already in use on this network. ";
+"The name has been changed to " = "The name has been changed to ";
+"." = ".";
-"The name has been changed to" = "The name has been changed to";
-"automatically." = "automatically.";
+"To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field." = "To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field.";
+"To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field." = "To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.";
-"To change the name of your computer, open System Preferences and click Sharing. Then type the name in the Computer Name field." = "To change the name of your computer, open System Preferences and click Sharing. Then type the name in the Computer Name field.";
-
-"To change the local hostname, open System Preferences and click Sharing. Then click Edit and type the name in the Local Hostname field." = "To change the local hostname, open System Preferences and click Sharing. Then click Edit and type the name in the Local Hostname field.";
+"All attempts to find an available name by adding a number to the name were also unsuccessful." = "All attempts to find an available name by adding a number to the name were also unsuccessful.";
+"This may indicate a problem with the local network. Please inform your network administrator." = "This may indicate a problem with the local network. Please inform your network administrator.";
-"The name of your computer" = "Le nom de l’ordinateur";
-"This computer’s local hostname" = "Le nom d’hôte local de cet ordinateur";
-"is already in use on this network." = "est déjà utilié sur ce réseau.";
+"The name of your computer " = "Le nom de l’ordinateur ";
+"This computer’s local hostname " = "Le nom d’hôte local de cet ordinateur ";
+"“" = "“";
+"”" = "”";
+" is already in use on this network. " = " est déjà utilié sur ce réseau. ";
+"The name has been changed to " = "Le nom a été changé pa ";
+"." = ".";
-"The name has been changed to" = "Le non a été changé par";
-"automatically." = "automatiquement.";
+"To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field." = "Pour changer le nom de votre ordinateur, ouvrez Préférences Systèmes et cliquer Partage. Ensuite entrez le nom dans le champ Nom de l’ordinateur.";
+"To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field." = "Pour changer le nom d’hôte local, ouvrez Préférences Systèmes et cliquer Partage. Ensuite cliquer Modifier et entrez le nom dans le champ Nom local de l’ordinateur.";
-"To change the name of your computer, open System Preferences and click Sharing. Then type the name in the Computer Name field." = "Pour changer le nom de votre ordinateur, ouvrez Préférences Systèmes et cliquer Partage. Ensuite entrez le nom dans le champ Nom de l’ordinateur.";
-
-"To change the local hostname, open System Preferences and click Sharing. Then click Edit and type the name in the Local Hostname field." = "Pour changer le nom d’hôte local, ouvrez Préférences Systèmes et cliquer Partage. Ensuite cliquer Modifier et entrez le nom dans le champ Nom local de l’ordinateur.";
+"All attempts to find an available name by adding a number to the name were also unsuccessful." = "Toutes les tentatives de trouver un nom disponible en ajoutant un nombre au nom étaient également non réussies.";
+"This may indicate a problem with the local network. Please inform your network administrator." = "Ceci peut indiquer un problème avec le réseau local. Veuillez informer votre administrateur de réseau.";
-no_module:start
-no_module:__call_mod_init_funcs
-no_module:__start
-no_module:__dyld_func_lookup
-no_module:dyld_stub_binding_helper
-no_module:_main
-no_module:_LogMsgIdent
-no_module:_mDNS_vsnprintf
-no_module:_WriteLogMsg
-no_module:_mDNSDaemonInitialize
-no_module:_mDNSMacOSXSystemBuildNumber
-no_module:_mDNS_Init
-no_module:_mDNSPlatformTimeInit
-no_module:___udivdi3
-no_module:_mDNSRandom
-no_module:_mDNSPlatformRandomSeed
-no_module:_mDNSPlatformRawTime
-no_module:_mDNS_GrowCache_internal
-no_module:_LogMsg
-no_module:_uDNS_Init
-no_module:_mDNSPlatformMemZero
-no_module:_mDNSPlatformInit
-no_module:_mDNSPlatformInit_setup
-no_module:_mDNS_snprintf
-no_module:_mDNSPlatformInit_CanReceiveUnicast
-no_module:_mDNSPlatformStrLen
-no_module:_mDNSPlatformMemCopy
-no_module:_SetupSocket
-no_module:_mDNSPlatformUTC
-no_module:_UpdateInterfaceList
-no_module:_myGetIfAddrs
-no_module:_AddInterfaceToList
-no_module:_GetBSSID
-no_module:_SetupAddr
-no_module:_mallocL
-no_module:_validatelists
-no_module:_mDNSSameAddress
-no_module:_FindRoutableIPv4
-no_module:_GetUserSpecifiedFriendlyComputerName
-no_module:_GetUserSpecifiedLocalHostName
-no_module:_SameDomainLabel
-no_module:_mDNS_SetFQDN
-no_module:_AppendDomainLabel
-no_module:_DomainNameLength
-no_module:_AppendLiteralLabelString
-no_module:_SameDomainName
-no_module:_mDNS_Lock
-no_module:_mDNSPlatformLock
-no_module:_mDNS_Unlock
-no_module:_GetNextScheduledEvent
-no_module:_mDNSPlatformUnlock
-no_module:_SetupActiveInterfaces
-no_module:_SearchForInterfaceByName
-no_module:_mDNS_RegisterInterface
-no_module:_AdvertiseInterface
-no_module:_FindFirstAdvertisedInterface
-no_module:_mDNS_SetupResourceRecord
-no_module:_MakeDomainNameFromDNSNameString
-no_module:_AppendDNSNameString
-no_module:_mDNS_Register_internal
-no_module:_IsLocalDomain
-no_module:_InitializeLastAPTime
-no_module:_SetNextAnnounceProbeTime
-no_module:_GetRDLength
-no_module:_ValidateRData
-no_module:_DomainNameHashValue
-no_module:_RDataHashValue
-no_module:_SetTargetToHostName
-no_module:_SetNewRData
-no_module:_CompressedDomainNameLength
-no_module:_AcknowledgeRecord
-no_module:_IdenticalResourceRecord
-no_module:_CountMaskBits
-no_module:_SameRData
-no_module:_mDNSPlatformMemSame
-no_module:_WatchForNetworkChanges
-no_module:_WatchForPowerChanges
-no_module:_DynDNSConfigChanged
-no_module:_GetUserSpecifiedDDNSConfig
-no_module:_ReadDDNSSettingsFromConfFile
-no_module:_RegisterSplitDNS
-no_module:_GetDNSConfig
-no_module:_RegisterSearchDomains
-no_module:_GetSearchDomains
-no_module:_GetDSSearchDomains
-no_module:_IsPrivateV4Addr
-no_module:_mDNS_SetPrimaryInterfaceInfo
-no_module:_InitDNSConfig
-no_module:_mDNS_GetDomains
-no_module:_AppendDomainName
-no_module:_mDNS_StartQuery
-no_module:_mDNS_StartQuery_internal
-no_module:_CheckForSoonToExpireRecords
-no_module:_CacheGroupForName
-no_module:_FindDuplicateQuestion
-no_module:_SetSCPrefsBrowseDomain
-no_module:_RegisterBrowseDomainPTR
-no_module:_mDNS_Register
-no_module:_FreeARElemCallback
-no_module:_mDNSCoreInitComplete
-no_module:_mDNS_StatusCallback
-no_module:_RecordUpdatedNiceLabel
-no_module:_udsserver_init
-no_module:_udsSupportAddFDToEventLoop
-no_module:_InitLinkedList
-no_module:_AddToTail
-no_module:_mDNSDaemonIdle
-no_module:_mDNS_TimeNow
-no_module:_mDNS_Execute
-no_module:_AnswerNewLocalOnlyQuestion
-no_module:_uDNS_Execute
-no_module:_mDNSPlatformTimeNow
-no_module:_CheckNATMappings
-no_module:_CheckQueries
-no_module:_CheckRecordRegistrations
-no_module:_CheckServiceRegistrations
-no_module:_udsserver_idle
-no_module:_cf_callback
-no_module:_connect_callback
-no_module:_request_callback
-no_module:_read_msg
-no_module:_ConvertHeaderBytes
-no_module:_validate_message
-no_module:_handle_regservice_request
-no_module:_get_long
-no_module:_mDNSPlatformInterfaceIDfromInterfaceIndex
-no_module:_get_string
-no_module:_get_short
-no_module:_get_rdata
-no_module:_ChopSubTypes
-no_module:_FindFirstSubType
-no_module:_ConstructServiceName
-no_module:_CountExistingRegistrations
-no_module:_register_service_instance
-no_module:_AllocateSubTypes
-no_module:_mDNS_RegisterService
-no_module:_ServiceCallback
-no_module:_mDNSPlatformGetRegDomainList
-no_module:_mDNS_CopyDNameList
-no_module:_mDNS_FreeDNameList
-no_module:_deliver_error
-no_module:_dnssd_htonl
-no_module:_put_long
-no_module:_reset_connected_rstate
-no_module:_freeL
-no_module:_SendQueries
-no_module:_GetFirstActiveInterface
-no_module:_InitializeDNSMessage
-no_module:_putQuestion
-no_module:_putDomainNameAsLabels
-no_module:_FindCompressionPointer
-no_module:_GetNextActiveInterfaceID
-no_module:_PutResourceRecordTTLWithLimit
-no_module:_putRData
-no_module:_mDNSSendDNSMessage
-no_module:_mDNSPlatformSendUDP
-no_module:_mDNSAddrIsDNSMulticast
-no_module:_myCFSocketCallBack
-no_module:_myrecvfrom
-no_module:_mDNSCoreReceive
-no_module:_mDNSCoreReceiveQuery
-no_module:_ProcessQuery
-no_module:_AddressIsLocalSubnet
-no_module:_getQuestion
-no_module:_getDomainName
-no_module:_ResourceRecordAnswersQuestion
-no_module:_ResolveSimultaneousProbe
-no_module:_LocateAuthorities
-no_module:_LocateAnswers
-no_module:_skipQuestion
-no_module:_skipDomainName
-no_module:_GetLargeResourceRecord
-no_module:_PacketRRConflict
-no_module:_MatchDependentOn
-no_module:_FindRRSet
-no_module:_AddAdditionalsToResponseList
-no_module:_NetworkChanged
-no_module:_MakeDomainLabelFromLiteralString
-no_module:_mDNSMacOSXNetworkChanged
-no_module:_MarkAllInterfacesInactive
-no_module:_ClearInactiveInterfaces
-no_module:_mDNS_DeregisterInterface
-no_module:_UpdateInterfaceProtocols
-no_module:_DeadvertiseInterface
-no_module:_mDNS_Deregister_internal
-no_module:_mDNS_HostNameCallback
-no_module:_CloseSocketSet
-no_module:_CloseRunLoopSourceSocket
-no_module:_NumCacheRecordsForInterfaceID
-no_module:_RegisterNameServers
-no_module:_mDNS_DeleteDNSServers
-no_module:_mDNS_AddDNSServer
-no_module:_mDNSPlatformMemAllocate
-no_module:_MarkSearchListElem
-no_module:_uDNS_StartQuery
-no_module:_startQuery
-no_module:_newMessageID
-no_module:_constructQueryMsg
-no_module:_initializeQuery
-no_module:_LinkActiveQuestion
-no_module:_uDNS_IsActiveQuery
-no_module:_GetServerForName
-no_module:_CountLabels
-no_module:_UpdateHostnameRegistrations
-no_module:_UpdateSRVRecords
-no_module:_GetStaticHostname
-no_module:_mDNS_UpdateLLQs
-no_module:_SuspendLLQs
-no_module:_CheckForUnreferencedLLQMapping
-no_module:_RestartQueries
-no_module:_udsserver_handle_configchange
-no_module:_rename_service
-no_module:_AnswerLocalQuestions
-no_module:_AnswerLocalOnlyQuestionWithResourceRecord
-no_module:_FoundDefBrowseDomain
-no_module:_DefaultBrowseDomainChanged
-no_module:_udsserver_default_browse_domain_changed
-no_module:_SendResponses
-no_module:_uDNS_ReceiveMsg
-no_module:_recvLLQResponse
-no_module:_simpleResponseHndlr
-no_module:_pktResponseHndlr
-no_module:_deriveGoodbyes
-no_module:_mDNSCoreReceiveResponse
-no_module:_kaListContainsAnswer
-no_module:_addKnownAnswer
-no_module:_FoundDomain
-no_module:_SameResourceRecord
-no_module:_mDNSPlatformMemFree
-no_module:_FoundStaticHostname
-no_module:_PacketRRMatchesSignature
-no_module:_CacheGroupForRecord
-no_module:_GetCacheGroup
-no_module:_GetCacheEntity
-no_module:_GetCacheRecord
-no_module:_CacheRecordAdd
-no_module:_SetNextCacheCheckTime
-no_module:_SameResourceRecordSignature
-no_module:_CacheRecordDeferredAdd
-no_module:_regservice_callback
-no_module:_process_service_registration
-no_module:_gen_rr_response
-no_module:_DeconstructServiceName
-no_module:_ConvertDomainLabelToCString_withescape
-no_module:_ConvertDomainNameToCString_withescape
-no_module:_create_reply
-no_module:_mDNSPlatformInterfaceIndexfromInterfaceID
-no_module:_put_string
-no_module:_send_msg
-no_module:_CountPeerRegistrations
-no_module:_CheckCacheExpiration
-no_module:_FindIdenticalRecordInCache
-no_module:_handle_browse_request
-no_module:_mDNSPlatformGetSearchDomainList
-no_module:_add_domain_to_browser
-no_module:_mDNS_StartBrowse
-no_module:_SetNextQueryTime
-no_module:_startLLQ
-no_module:_startGetZoneData
-no_module:_getZoneData
-no_module:_hndlLookupSOA
-no_module:_startInternalQuery
-no_module:_AnswerNewQuestion
-no_module:_ExpireDupSuppressInfo
-no_module:_SuppressOnThisInterface
-no_module:_BuildQuestion
-no_module:_uDNS_StopQuery
-no_module:_processSOA
-no_module:_confirmNS
-no_module:_lookupNSAddr
-no_module:_LocateAdditionals
-no_module:_skipResourceRecord
-no_module:_hndlLookupPorts
-no_module:_lookupDNSPort
-no_module:_startLLQHandshakeCallback
-no_module:_mDNS_GrowCache
-no_module:_AnswerQuestionWithResourceRecord
-no_module:_browse_result_callback
-no_module:_DNSTypeName
-no_module:_GetRRDisplayString_rdb
-no_module:_append_reply
-no_module:_llqResponseHndlr
-no_module:_AccelerateThisQuery
-no_module:_ReconfirmAntecedents
-no_module:_handle_enum_request
-no_module:_format_enumeration_reply
-no_module:_enum_result_callback
-no_module:_ReleaseCacheRecord
-no_module:_ReleaseCacheEntity
-no_module:_AddRecordToResponseList
-no_module:_ShouldSuppressKnownAnswer
-no_module:_RecordDupSuppressInfo
-no_module:_ReleaseCacheGroup
-no_module:_CacheRecordRmv
-no_module:_hndlTruncatedAnswer
-no_module:_mDNSPlatformTCPConnect
-no_module:_tcpCFSocketCallback
-no_module:_conQueryCallback
-no_module:_mDNSPlatformWriteTCP
-no_module:_mDNSPlatformReadTCP
-no_module:_mDNSPlatformTCPCloseConnection
-no_module:_handle_add_request
-no_module:_add_record_to_service
-no_module:_mDNS_AddRecordToService
-no_module:_handle_update_request
-no_module:_update_record
-no_module:_mDNS_Update
-no_module:_handle_query_request
-no_module:_question_result_callback
-no_module:_put_short
-no_module:_put_rdata
-no_module:_abort_request
-no_module:_question_termination_callback
-no_module:_mDNS_StopQuery
-no_module:_mDNS_StopQuery_internal
-no_module:_UpdateQuestionDuplicates
-no_module:_udsSupportRemoveFDFromEventLoop
-no_module:_RemoveFromList
-no_module:_unlink_request
-no_module:_DNSserverCallback
-no_module:_DNSServiceDiscoveryRequest_server
-no_module:__XDNSServiceResolverResolve_rpc
-no_module:___MIG_check__Request__DNSServiceResolverResolve_rpc_t
-no_module:_provide_DNSServiceResolverResolve_rpc
-no_module:_CheckForExistingClient
-no_module:_mDNS_StartResolveService
-no_module:_EnableDeathNotificationForClient
-no_module:_FoundServiceInfoSRV
-no_module:_MachineHasActiveIPv6
-no_module:_FoundServiceInfoTXT
-no_module:_FoundServiceInfo
-no_module:_FoundInstanceInfo
-no_module:_DNSServiceResolverReply_rpc
-no_module:_ExpireDupSuppressInfoOnInterface
-no_module:_CompleteRDataUpdate
-no_module:_update_callback
-no_module:_GenerateUnicastResponse
-no_module:_PutResourceRecordCappedTTL
-no_module:_ClientDeathCallback
-no_module:_AbortClient
-no_module:_mDNS_StopResolveService
-no_module:_mDNS_Reconfirm_internal
-no_module:_browse_termination_callback
-no_module:_stopLLQ
-no_module:_GrantUpdateCredit
-no_module:__XDNSServiceBrowserCreate_rpc
-no_module:___MIG_check__Request__DNSServiceBrowserCreate_rpc_t
-no_module:_provide_DNSServiceBrowserCreate_rpc
-no_module:_AddDomainToBrowser
-no_module:_FoundInstance
-no_module:_DNSServiceBrowserReply_rpc
-no_module:__XDNSServiceRegistrationCreate_rpc
-no_module:___MIG_check__Request__DNSServiceRegistrationCreate_rpc_t
-no_module:_provide_DNSServiceRegistrationCreate_rpc
-no_module:_AddServiceInstance
-no_module:_RegCallback
-no_module:_DNSServiceRegistrationReply_rpc
-no_module:_mDNS_DeregisterService
-no_module:_CompleteDeregistration
-no_module:_FreeServiceInstance
-no_module:_PowerChanged
-no_module:_mDNSCoreMachineSleep
-no_module:_uDNS_Sleep
-no_module:_SleepServiceRegistrations
-no_module:_SleepRecordRegistrations
-no_module:_PurgeCacheResourceRecord
-no_module:_regservice_termination_callback
-no_module:_free_service_instance
-no_module:_FreeExtraRR
-no_module:_mDNS_Deregister
-no_module:_uDNS_Wake
-no_module:_WakeServiceRegistrations
-no_module:_WakeRecordRegistrations
-no_module:_SendDelayedUnicastResponse
-no_module:_mDNS_RenameAndReregisterService
-no_module:_FindNextSubType
-no_module:_handle_removerecord_request
+start
+_start
+_dyld_func_lookup
+main
+LogMsg
+mDNS_vsnprintf
+WriteLogMsg
+LogMsgIdent
+KQueueSet
+mDNSMacOSXSystemBuildNumber
+mDNS_Init
+mDNSPlatformTimeInit
+mDNSRandom
+mDNSPlatformRandomSeed
+mDNSPlatformRawTime
+mDNSPlatformInit
+GetUserSpecifiedLocalHostName
+mDNS_snprintf
+SetupSocket
+UpdateInterfaceList
+myGetIfAddrs
+AddInterfaceToList
+SetupAddr
+mDNSSameAddress
+mDNS_SetFQDN
+AppendDomainLabel
+AppendLiteralLabelString
+SameDomainNameCS
+mDNS_Lock
+mDNSPlatformLock
+DomainNameLengthLimit
+mDNSPlatformMemCopy
+mDNS_Unlock
+mDNSPlatformUnlock
+SetupActiveInterfaces
+mDNS_RegisterInterface
+AdvertiseInterface
+mDNS_SetupResourceRecord
+MakeDomainNameFromDNSNameString
+AppendDNSNameString
+mDNS_Register_internal
+InitializeLastAPTime
+SetNextAnnounceProbeTime
+GetRDLength
+ValidateRData
+DomainNameHashValue
+RDataHashValue
+SetTargetToHostName
+SameDomainName
+SetNewRData
+CompressedDomainNameLength
+AcknowledgeRecord
+IdenticalResourceRecord
+SetDomainSecrets
+mDNSKeychainGetSecrets
+getHelperPort
+proxy_mDNSKeychainGetSecrets
+mDNSDynamicStoreSetConfig
+proxy_mDNSDynamicStoreSetConfig
+mDNSCoreInitComplete
+mDNS_StatusCallback
+mDNSPlatformMemSame
+uDNS_SetupDNSConfig
+mDNSPlatformSetDNSConfig
+dns_configuration_copy
+_dns_configuration_server_port
+shared_dns_infoGet
+dns_configuration_free
+mDNSPlatformGetPrimaryInterface
+mDNS_SetPrimaryInterfaceInfo
+udsserver_init
+mDNSPlatformMemZero
+mDNSPlatformStrCopy
+udsSupportAddFDToEventLoop
+mDNS_GetDomains
+AppendDomainName
+mDNS_StartQuery
+mDNS_StartQuery_internal
+CheckForSoonToExpireRecords
+FindDuplicateQuestion
+GetAuthInfoForName
+RegisterLocalOnlyDomainEnumPTR
+mDNSPlatformMemAllocate
+mDNS_Register
+AddAutoBrowseDomain
+udsserver_automatic_browse_domain_changed
+machserver_automatic_browse_domain_changed
+udsserver_handle_configchange
+UpdateDeviceInfoRecord
+KQueueLoop
+mDNS_TimeNow
+mDNS_Execute
+uDNS_Execute
+mDNSv4AddrIsRFC1918
+udsserver_idle
+NetworkChanged
+KQueueLock
+KQueueUnlock
+KQWokenFlushBytes
+connect_callback
+NewRequest
+request_callback
+read_msg
+ConvertHeaderBytes
+handle_enum_request
+get_uint32
+mDNSPlatformInterfaceIDfromInterfaceIndex
+uDNS_RegisterSearchDomains
+put_uint32
+send_all
+mDNSMacOSXNetworkChanged
+ClearInactiveInterfaces
+GetFirstActiveInterface
+InitializeDNSMessage
+putQuestion
+putDomainNameAsLabels
+FindCompressionPointer
+PutResourceRecordTTLWithLimit
+putRData
+mDNSSendDNSMessage
+mDNSPlatformSendUDP
+mDNSAddrIsDNSMulticast
+myKQSocketCallBack
+mDNSCoreReceive
+AddressIsLocalSubnet
+getQuestion
+getDomainName
+ResourceRecordAnswersQuestion
+LocateAuthorities
+GetLargeResourceRecord
+PacketRRConflict
+SameRData
+SameRDataBody
+AddAdditionalsToResponseList
+SendResponses
+mDNSCoreReceiveResponse
+uDNS_recvLLQResponse
+LocateAnswers
+CreateNewCacheEntry
+GetCacheEntity
+SetNextCacheCheckTime
+CacheRecordDeferredAdd
+IdenticalSameNameRecord
+mDNS_HostNameCallback
+SameResourceRecordSignature
+AnswerLocalQuestions
+AnswerLocalOnlyQuestionWithResourceRecord
+enum_result_callback
+ConvertDomainNameToCString_withescape
+ConvertDomainLabelToCString_withescape
+create_reply
+put_string
+CheckCacheExpiration
+AbortUnlinkAndFree
+abort_request
+enum_termination_callback
+mDNS_StopQuery
+mDNS_StopQuery_internal
+udsSupportRemoveFDFromEventLoop
+get_string
+ChopSubTypes
+add_domain_to_browser
+mDNS_StartBrowse
+ConstructServiceName
+IsLocalDomain
+GetNextActiveInterfaceID
+ReconfirmAntecedents
+mDNS_DeregisterInterface
+DeadvertiseInterface
+mDNS_Deregister_internal
+NumCacheRecordsForInterfaceID
+mDNS_UpdateLLQs
+SuspendLLQs
+RestartQueries
+mDNS_AddSearchDomain
+mDNS_NewMessageID
+GetServerForName
+ActivateUnicastQuery
+AddrRequiresPPPConnection
+mDNS_AddDNSServer
+SetExternalAddress
+UpdateSRVRecords
+ReleaseCacheRecord
+ReleaseCacheGroup
+uDNS_CheckCurrentQuestion
+NoTestQuery
+uDNS_ReceiveMsg
+GetLLQOptData
+LocateLLQOptData
+LocateAdditionals
+AnswerCurrentQuestionWithResourceRecord
+FoundInstance
+GenerateNTDResponse
+DeconstructServiceName
+mDNSPlatformInterfaceIndexfromInterfaceID
+get_uint16
+constructQueryMsg
+skipResourceRecord
+FoundDomain
+FreeARElemCallback
+SameNameRecordAnswersQuestion
+queryrecord_result_callback
+put_uint16
+queryrecord_termination_callback
+FoundStaticHostname
+AutomaticBrowseDomainChange
+FindIdenticalRecordInCache
+MakeDomainLabelFromLiteralString
+register_service_instance
+AllocateSubTypes
+mDNS_RegisterService
+ServiceCallback
+regservice_callback
+KeychainChanged
+mDNS_SetSecretForDomain
+DNSDigest_ConstructHMACKeyfromBase64
+StartGetZoneData
+GetZoneData_StartQuery
+AppendDNameListElem
+SetPrefsBrowseDomains
+udsserver_default_reg_domain_changed
+machserver_automatic_registration_domain_changed
+GetServiceTarget
+SetupLocalAutoTunnelInterface_internal
+mDNSAutoTunnelInterfaceUpDown
+proxy_mDNSAutoTunnelInterfaceUpDown
+mDNS_AddDynDNSHostName
+AdvertiseHostname
+mDNS_StartNATOperation_internal
+mDNSConfigureServer
+proxy_mDNSConfigureServer
+mDNSPlatformUDPSocket
+uDNS_SendNATMsg
+LNT_SendDiscoveryMsg
+uDNS_ReceiveNATPMPPacket
+natTraversalHandleAddressReply
+hostnameGetPublicAddressCallback
+natTraversalHandlePortMapReply
+AutoTunnelNATCallback
+GetZoneData_QuestionCallback
+startLLQHandshakeCallback
+startLLQHandshake
+StartLLQNatMap
+mDNSPlatformMemFree
+RecordRegistrationCallback
+sendRecordRegistration
+putZone
+putDeleteRRSet
+putUpdateLease
+MakeTCPConn
+mDNSPlatformTCPSocket
+mDNSPlatformTCPConnect
+tcpKQSocketCallback
+tlsSetupSock
+tlsWriteSock
+tlsReadSock
+LLQNatMapComplete
+mDNS_GrowCache
+tcpCallback
+DNSDigest_SignMessage
+MD5_Update
+md5_block_host_order
+mDNSPlatformUTC
+MD5_Final
+mDNSPlatformWriteTCP
+putLLQ
+serviceRegistrationCallback
+SendServiceRegistration
+putPrereqNameNotInUse
+putEmptyResourceRecord
+mDNSPlatformReadTCP
+DisposeTCPConn
+mDNSPlatformTCPCloseConnection
+GetPktLease
+LocateLeaseOptData
+checkUpdateResult
+GetRRDisplayString_rdb
+startPrivateQueryCallback
+HostnameCallback
+UpdateSRV
+SendServiceDeregistration
+putDeleteAllRRSets
+putDeletionRecord
+StartSRVNatMap
+SameDomainLabel
+CompleteSRVNatMap
+PowerChanged
+mDNSCoreMachineSleep
+uDNS_Sleep
+sendLLQRefresh
+mDNS_StopNATOperation_internal
+mDNS_Reconfirm_internal
+mDNSRandomFromFixedSeed
+DeregisterLocalOnlyDomainEnumPTR
+mDNS_Deregister
+RmvAutoBrowseDomain
+uDNS_Wake
+uDNS_DeregisterRecord
+MakeNegativeCacheRecord
+CompleteDeregistration
+mDNSPlatformUDPClose
+CloseSocketSet
+CancelGetZoneData
+SendRecordDeregistration
+mDNSPlatformStrLen
+TruncateUTF8ToLength
+get_rdata
+mDNS_AddRecordToService
+update_record
+mDNS_Update
+CompleteRDataUpdate
+update_callback
+ShouldSuppressKnownAnswer
+handle_resolve_request
+resolve_result_callback
+put_rdata
+resolve_termination_callback
+regservice_termination_callback
+mDNS_DeregisterService
+browse_termination_callback
+free_service_instance
+FreeExtraRR
+SetNextQueryTime
+AddNewClientTunnel
+AutoTunnelCallback
+FindSourceAddrForIP
+AutoTunnelSetKeys
+mDNSAutoTunnelSetKeys
+proxy_mDNSAutoTunnelSetKeys
+ReissueBlockedQuestions
+read_rr_from_ipc_msg
+CountPeerRegistrations
+RecordUpdatedNiceLabel
+regrecord_callback
+handle_port_mapping_request
+mDNS_StartNATOperation
+port_mapping_create_request_callback
+DNSTypeName
+mDNS_StopQueryWithRemoves
+uDNS_StopLongLivedQuery
+uDNS_ReceiveSSDPPacket
+LNT_ConfigureRouterInfo
+MakeTCPConnection
+tcpConnectionCallback
+LNT_GetExternalAddress
+SendSOAPMsgControlAction
+LNT_MapPort
+LNT_UnmapPort
+PutResourceRecordCappedTTL
+connection_termination
+uDNS_DeregisterService
+SendServiceRemovalNotification
+mDNS_RemoveDynDNSHostName
+mDNS_StopNATOperation
+unlinkSRS
+DDNSSettingEnabled
+sendChallengeResponse
+mDNSPlatformDynDNSHostNameStatusChanged
+UnlinkAuthRecord
+DynDNSHostNameCallback
+port_mapping_termination_callback
+SendDelayedUnicastResponse
+RecordProbeFailure
+mDNS_RenameAndReregisterService
+IncrementLabelSuffix
+LabelContainsSuffix
+AppendLabelSuffix
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
- HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${OBJROOT}/mDNSResponder.build\"";
- LIBRARY_SEARCH_PATHS = "\"${OBJROOT}/mDNSResponder.build\"";
+ HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
MACOSX_DEPLOYMENT_TARGET = 10.2;
OPTIMIZATION_CFLAGS = "-O0";
- OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS} -DMDNS_DEBUGMSGS=1";
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -DmDNSResponderVersion=${MVERS} -DAPPLE_OSX_mDNSResponder=1 -D_LEGACY_NAT_TRAVERSAL_ -DMDNS_DEBUGMSGS=1";
OTHER_LDFLAGS = "-ldnsinfo";
OTHER_REZFLAGS = "";
PRODUCT_NAME = mDNSResponder.debug;
F5E11B5E04A28126019798ED,
FFCB6D75075D595E00B8AF62,
00AD62B0032D799A0CCA2C71,
+ 7FC8F9D606D14E66007E879D,
00AD62B1032D799A0CCA2C71,
);
isa = PBXSourcesBuildPhase;
buildRules = (
);
buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
MVERS = "\"mDNSResponder (Engineering Build)\"";
};
isa = PBXBuildStyle;
};
08FB7795FE84155DC02AAC07 = {
children = (
+ 7FC8F9D406D14E66007E879D,
7F461DB5062DBF2900672BF3,
F525E72804AA167501F1CF4D,
F5E11B5A04A28126019798ED,
7F18A9F60587CEF6001880B3,
7F18A9F70587CEF6001880B3,
FF25794606C9A8BF00376F7B,
- FF25794C06C9A9D500376F7B,
- FF25794F06C9AA8B00376F7B,
+ FF13FFEA0A5DA44A00897C81,
+ FF13FFEC0A5DA45500897C81,
);
isa = PBXGroup;
name = "mDNS Server Sources";
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
- HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${OBJROOT}/mDNSResponder.build\"";
+ HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
INSTALL_PATH = /usr/sbin;
- LIBRARY_SEARCH_PATHS = "\"${OBJROOT}/mDNSResponder.build\"";
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
MACOSX_DEPLOYMENT_TARGET = 10.2;
- OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}";
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -DmDNSResponderVersion=${MVERS} -DAPPLE_OSX_mDNSResponder=1 -D_LEGACY_NAT_TRAVERSAL_ -D__MigTypeCheck=1";
OTHER_LDFLAGS = "-ldnsinfo";
OTHER_REZFLAGS = "";
PRODUCT_NAME = mDNSResponder;
F5E11B5C04A28126019798ED,
FFCB6D74075D539900B8AF62,
6575FBED022EAF7200000109,
+ 7FC8F9D506D14E66007E879D,
6575FBEE022EAF7200000109,
);
isa = PBXSourcesBuildPhase;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INSTALL_PATH = /usr/bin;
MACOSX_DEPLOYMENT_TARGET = 10.2;
- OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}";
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic";
OTHER_LDFLAGS = "";
OTHER_REZFLAGS = "";
PRODUCT_NAME = mDNS;
settings = {
};
};
+ 7FC8F9D406D14E66007E879D = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = LegacyNATTraversal.c;
+ refType = 2;
+ };
+ 7FC8F9D506D14E66007E879D = {
+ fileRef = 7FC8F9D406D14E66007E879D;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7FC8F9D606D14E66007E879D = {
+ fileRef = 7FC8F9D406D14E66007E879D;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
//7F0
//7F1
//7F2
DB2CC44D0662DD1100335AB3,
DB2CC44E0662DD1100335AB3,
DB2CC44F0662DD1100335AB3,
+ FF2C5FB00A48B8680066DA11,
+ FF2C5FB20A48B86E0066DA11,
);
isa = PBXGroup;
name = "Java Support";
DB2CC45F0662DE4C00335AB3,
DB2CC4600662DE4C00335AB3,
DB2CC4610662DE4D00335AB3,
+ FF2C5FB10A48B8680066DA11,
+ FF2C5FB30A48B86E0066DA11,
);
isa = PBXSourcesBuildPhase;
runOnlyForDeploymentPostprocessing = 0;
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "if [ -d ${OBJROOT}/mDNSResponder.build/${CONFIGURATION} ]; then BUILD_DIR=${OBJROOT}/mDNSResponder.build/${CONFIGURATION}; else BUILD_DIR=${OBJROOT}/mDNSResponder.build; fi\njavah -force -J-Xbootclasspath/p:${BUILD_DIR}/dns_sd.jar.build/JavaClasses -o ${BUILD_DIR}/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService";
+ shellScript = "javah -force -J-Xbootclasspath/p:${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/JavaClasses -o ${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService";
};
DB2CC4560662DE4500335AB3 = {
fileRef = DB2CC4430662DD1100335AB3;
DB2CC4650662DF5C00335AB3,
);
buildSettings = {
- DEBUGGING_SYMBOLS = NO;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
- HEADER_SEARCH_PATHS = "../mDNSShared \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers\" \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers\" \"${OBJROOT}/mDNSResponder.build/dns_sd.jar.build\" \"${OBJROOT}/mDNSResponder.build/${CONFIGURATION}/dns_sd.jar.build\"";
+ HEADER_SEARCH_PATHS = "../mDNSShared \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers\" \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers\" \"${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build\"";
INSTALL_PATH = /usr/lib/java;
LIBRARY_STYLE = DYNAMIC;
MACOSX_DEPLOYMENT_TARGET = 10.2;
path = ../mDNSShared/mDNS.1;
refType = 2;
};
+ FF13FFE90A5DA40200897C81 = {
+ fileRef = 6575FBEB022EAF7200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF13FFEA0A5DA44A00897C81 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = dnsextd_lexer.l;
+ path = ../mDNSShared/dnsextd_lexer.l;
+ refType = 2;
+ };
+ FF13FFEB0A5DA44A00897C81 = {
+ fileRef = FF13FFEA0A5DA44A00897C81;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF13FFEC0A5DA45500897C81 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = dnsextd_parser.y;
+ path = ../mDNSShared/dnsextd_parser.y;
+ refType = 2;
+ };
+ FF13FFED0A5DA45500897C81 = {
+ fileRef = FF13FFEC0A5DA45500897C81;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF13FFEE0A5DA52700897C81 = {
+ isa = PBXTargetDependency;
+ target = 08FB779FFE84155DC02AAC07;
+ };
+ FF13FFEF0A5DA6FD00897C81 = {
+ fileRef = FFCB6D73075D539900B8AF62;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
FF16238F07023BD2001AB7D7 = {
isa = PBXTargetDependency;
target = FF1C919207021C84001048AB;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INSTALL_PATH = /usr/bin;
MACOSX_DEPLOYMENT_TARGET = 10.2;
- OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS} -I../mDNSShared";
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -I../mDNSShared";
OTHER_LDFLAGS = "";
OTHER_REZFLAGS = "";
PRODUCT_NAME = "dns-sd";
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
- HEADER_SEARCH_PATHS = "\"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\"";
+ HEADER_SEARCH_PATHS = "\"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
INSTALL_PATH = /usr/sbin;
- LIBRARY_SEARCH_PATHS = "";
+ LEX = /usr/bin/flex;
+ LEXFLAGS = "-i";
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
MACOSX_DEPLOYMENT_TARGET = 10.2;
- OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}";
- OTHER_LDFLAGS = "";
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic";
+ OTHER_LDFLAGS = "-ldnsinfo";
OTHER_REZFLAGS = "";
PRODUCT_NAME = dnsextd;
REZ_EXECUTABLE = YES;
SECTORDER_FLAGS = "";
STRIPFLAGS = "-S";
WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+ YACC = "/usr/bin/bison -y";
};
dependencies = (
+ FF13FFEE0A5DA52700897C81,
);
isa = PBXToolTarget;
name = dnsextd;
buildActionMask = 2147483647;
files = (
FF25792B06C9A70800376F7B,
- FF25792C06C9A70800376F7B,
);
isa = PBXHeadersBuildPhase;
runOnlyForDeploymentPostprocessing = 0;
settings = {
};
};
- FF25792C06C9A70800376F7B = {
- fileRef = F5E11B5B04A28126019798ED;
- isa = PBXBuildFile;
- settings = {
- };
- };
FF25792D06C9A70800376F7B = {
buildActionMask = 2147483647;
files = (
FF25793606C9A70800376F7B,
FF25793806C9A70800376F7B,
FF25794706C9A8BF00376F7B,
- FF25794906C9A97400376F7B,
FF25794A06C9A98700376F7B,
- FF25794D06C9A9D500376F7B,
FF25794E06C9AA3000376F7B,
- FF25795006C9AA8B00376F7B,
+ FF13FFE90A5DA40200897C81,
+ FF13FFEB0A5DA44A00897C81,
+ FF13FFED0A5DA45500897C81,
+ FF13FFEF0A5DA6FD00897C81,
);
isa = PBXSourcesBuildPhase;
runOnlyForDeploymentPostprocessing = 0;
fileEncoding = 4;
isa = PBXFileReference;
name = dnsextd.c;
- path = ../mDNSPosix/dnsextd.c;
+ path = ../mDNSShared/dnsextd.c;
refType = 2;
};
FF25794706C9A8BF00376F7B = {
settings = {
};
};
- FF25794906C9A97400376F7B = {
- fileRef = 7F18A9F70587CEF6001880B3;
- isa = PBXBuildFile;
- settings = {
- };
- };
FF25794A06C9A98700376F7B = {
fileRef = DBAAFE29057E8F4D0085CAD0;
isa = PBXBuildFile;
settings = {
};
};
- FF25794C06C9A9D500376F7B = {
- fileEncoding = 4;
- isa = PBXFileReference;
- name = mDNSPosix.c;
- path = ../mDNSPosix/mDNSPosix.c;
- refType = 2;
- };
- FF25794D06C9A9D500376F7B = {
- fileRef = FF25794C06C9A9D500376F7B;
- isa = PBXBuildFile;
- settings = {
- };
- };
FF25794E06C9AA3000376F7B = {
fileRef = DBAAFE2C057E8F660085CAD0;
isa = PBXBuildFile;
settings = {
};
};
- FF25794F06C9AA8B00376F7B = {
- fileEncoding = 4;
- isa = PBXFileReference;
- name = mDNSUNP.c;
- path = ../mDNSPosix/mDNSUNP.c;
- refType = 2;
- };
- FF25795006C9AA8B00376F7B = {
- fileRef = FF25794F06C9AA8B00376F7B;
- isa = PBXBuildFile;
- settings = {
- };
- };
FF25795106C9AB1D00376F7B = {
isa = PBXTargetDependency;
target = FF25792906C9A70800376F7B;
isa = PBXTargetDependency;
target = FF2609E107B440DD00CE10E5;
};
+ FF2C5FB00A48B8680066DA11 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSSDRecordRegistrar.java;
+ path = ../mDNSShared/Java/DNSSDRecordRegistrar.java;
+ refType = 2;
+ };
+ FF2C5FB10A48B8680066DA11 = {
+ fileRef = FF2C5FB00A48B8680066DA11;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2C5FB20A48B86E0066DA11 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = RegisterRecordListener.java;
+ path = ../mDNSShared/Java/RegisterRecordListener.java;
+ refType = 2;
+ };
+ FF2C5FB30A48B86E0066DA11 = {
+ fileRef = FF2C5FB20A48B86E0066DA11;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
FF354EB108516C63007C00E1 = {
fileEncoding = 4;
isa = PBXExecutableFileReference;
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${OBJROOT}/mDNSResponder.build/dnsinfo.h\"\nrm -f \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${OBJROOT}/mDNSResponder.build/dnsinfo.h\ntouch ${OBJROOT}/mDNSResponder.build/empty.c\ncc ${OBJROOT}/mDNSResponder.build/empty.c -c -o \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nrm -f ${OBJROOT}/mDNSResponder.build/empty.c\nfi";
+ shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi";
};
FF485D5105632E0000130380 = {
fileEncoding = 4;
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "rm -f ${BUILD_DIR}/${CONFIGURATION}/dns_sd";
+ shellScript = "rm -f ${CONFIGURATION_BUILD_DIR}/dns_sd";
};
FFD41DDF06641BBB00F0C438 = {
isa = PBXTargetDependency;
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${OBJROOT}/mDNSResponder.build/dnsinfo.h\"\nrm -f \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${OBJROOT}/mDNSResponder.build/dnsinfo.h\ntouch ${OBJROOT}/mDNSResponder.build/empty.c\ncc ${OBJROOT}/mDNSResponder.build/empty.c -c -o \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nrm -f ${OBJROOT}/mDNSResponder.build/empty.c\nfi";
+ shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi";
};
FFFB0DA407B43BED00B88D48 = {
children = (
FFFB0DA807B43C9100B88D48,
);
buildSettings = {
+ INSTALL_PATH = "/Library/Application Support/Bonjour";
MACOSX_DEPLOYMENT_TARGET = 10.2;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
);
isa = PBXToolTarget;
name = ddnswriteconfig;
- productInstallPath = /usr/local/bin;
+ productInstallPath = "/Library/Application Support/Bonjour";
productName = ddnswriteconfig;
productReference = FFFB0DAA07B43C9100B88D48;
};
--- /dev/null
+; -*- Mode: Scheme; tab-width: 4 -*-
+;
+; Copyright (c) 2007 Apple Inc. All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+;
+; 1. Redistributions of source code must retain the above copyright notice,
+; this list of conditions and the following disclaimer.
+; 2. Redistributions in binary form must reproduce the above copyright notice,
+; this list of conditions and the following disclaimer in the documentation
+; and/or other materials provided with the distribution.
+; 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+; contributors may be used to endorse or promote products derived from this
+; software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;
+; $Log: mDNSResponder.sb,v $
+; Revision 1.24 2007/09/20 22:33:17 cheshire
+; Tidied up inconsistent and error-prone naming -- used to be mDNSResponderHelper in
+; some places and mDNSResponder.helper in others; now mDNSResponderHelper everywhere
+;
+; Revision 1.23 2007/09/04 22:26:18 mcguire
+; <rdar://problem/5442826> Seatbelt: mDNSResponder needs to be allowed to access "/Library/Security/Trust Settings/" etc.
+;
+; Revision 1.22 2007/08/24 22:01:56 mcguire
+; <rdar://problem/5141606> BTMM: Task: Change mDNSResponder Seatbelt settings to "deny default" instead of "signal FPE" just prior to GM candidate
+;
+; Revision 1.21 2007/08/18 01:02:03 mcguire
+; <rdar://problem/5415593> No Bonjour services are getting registered at boot
+;
+; Revision 1.20 2007/08/08 22:34:59 mcguire
+; <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+;
+; Revision 1.19 2007/07/02 23:37:50 cheshire
+; <rdar://problem/5267615> Need to list of allowed mach-lookup operations explicitly in mDNSResponder.sb
+;
+; Revision 1.18 2007/06/28 20:43:35 cheshire
+; <rdar://problem/5298202> Seatbelt: mDNSResponder needs to be able to access /dev/autofs_nowait
+;
+; Revision 1.17 2007/06/28 20:34:45 cheshire
+; Updated comments to reflect new seatbelt language syntax
+;
+; Revision 1.16 2007/05/29 23:32:46 cheshire
+; Rearrange file so SPI warning isn't deleted when CVS history is trimmed from installed copy
+;
+; Revision 1.15 2007/05/25 22:45:17 jvidrine
+; <rdar://problem/5227658> Update mDNSResponder.sb to Seatbelt Profile Language version 1
+;
+; Revision 1.14 2007/05/23 17:40:08 cheshire
+; <rdar://problem/5221397> Seatbelt killed mDNSResponder trying to read X509Anchors and X509Certificates
+;
+; Revision 1.13 2007/05/23 01:47:59 cheshire
+; Need to list fs_read_data permission explicitly --
+; unlike fs_read/fs_write, fs_read_data does NOT automatically inherit from fs_write_data
+;
+; Revision 1.12 2007/05/21 23:52:27 cheshire
+; <rdar://problem/5216638> Seatbelt killed mDNSResponder generating Module Directory Services cache
+;
+; Revision 1.11 2007/05/20 16:29:06 cheshire
+; <rdar://problem/5213725> Seatbelt killed mDNSResponder trying to access /usr/share/icu/icudt36l.dat
+;
+; Revision 1.10 2007/05/15 00:21:39 cheshire
+; <rdar://problem/5202374> Seatbelt killed mDNSResponder reading /private/var/root/Library/Preferences/com.apple.security.plist
+;
+; Revision 1.9 2007/05/14 22:08:26 cheshire
+; <rdar://problem/5200986> Seatbelt: Need to escape literal dots in filename patterns
+;
+; Revision 1.8 2007/05/14 19:39:31 cheshire
+; <rdar://problem/5198345> Seatbelt killed mDNSResponder in CFTimeZoneCopyDefault
+; <rdar://problem/5199456> Seatbelt killed mDNSResponder in SecKeychainOpen
+;
+; Revision 1.7 2007/05/12 01:57:56 cheshire
+; <rdar://problem/5197938> Seatbelt: mDNSResponder needs to be able to access preferences.plist-lock
+;
+; Revision 1.6 2007/05/10 21:12:14 cheshire
+; <rdar://problem/5149833> Start using "debug deny" mode in Seatbelt
+;
+; Revision 1.5 2007/05/10 19:41:25 cheshire
+; <rdar://problem/5182549> Have to use "deny mach_lookup_default" because "signal" doesn't work
+;
+; Revision 1.4 2007/04/27 20:46:31 cheshire
+; Additional requirements: allow mDNSResponder to read /dev/random and /System/Library/Keychains/System.*
+;
+; Revision 1.3 2007/04/20 19:42:14 cheshire
+; Condense rules a bit to bring file under Seatbelt's 4K limit
+;
+; Revision 1.2 2007/04/19 01:47:49 cheshire
+; Refinements to sandbox profile, e.g. allow writing to /dev/console early in the boot process
+;
+; Revision 1.1 2007/04/18 00:50:47 cheshire
+; <rdar://problem/5141540> Sandbox mDNSResponder
+;
+;############################################################################
+
+; WARNING! SEATBELT CURRENTLY CAN'T HANDLE PROFILES LARGER THAN 16K
+; MAKE SURE THE SIZE OF THIS FILE FROM "version" TO THE END DOESN'T EXCEED 16K
+
+(version 1)
+
+; WARNING: The sandbox rule capabilities and syntax used in this file are currently an
+; Apple SPI (System Private Interface) and are subject to change at any time without notice.
+; Apple may in future announce an official public supported sandbox API, but until then Developers
+; are cautioned not to build products that use or depend on the sandbox facilities illustrated here.
+
+; Use "debug all" to log all operations examined by seatbelt, whether allowed or not.
+; Use "debug deny" to log only operations that are denied by seatbelt
+; to discover what specific attempted operation is causing an exception.
+
+;(debug all)
+(debug deny)
+
+; To help debugging, "with send-signal SIGFPE" will trigger a fake floating-point exception,
+; which will crash the process and show the call stack leading to the offending operation.
+; For the shipping version "deny" is probably better because it vetoes the operation
+; without killing the process.
+
+(deny default)
+;(deny default (with send-signal SIGFPE))
+
+; Special exception: "send-signal" command does not apply to the mach-* operations,
+; so for those we have to use a plain unadorned "deny" instead
+; (which means we may not get any notification of unintentional mach-* denials)
+(deny mach-lookup)
+(deny mach-priv-host-port)
+
+; Mach communications
+; These are needed for things like getpwnam, hostname changes, & keychain
+(allow mach-lookup (global-name
+ "com.apple.bsd.dirhelper"
+ "com.apple.distributed_notifications.2"
+ "com.apple.ocspd"
+ "com.apple.mDNSResponderHelper"
+ "com.apple.SecurityServer"
+ "com.apple.SystemConfiguration.configd"
+ "com.apple.system.DirectoryService.libinfo_v1"
+ "com.apple.system.notification_center"))
+
+; Rules to allow the operations mDNSResponder needs start here
+
+(allow network*) ; Allow networking, including Unix Domain Sockets
+(allow sysctl-read) ; To get hardware model information
+(allow file-read-metadata) ; Needed for dyld to work
+(allow ipc-posix-shm) ; Needed for POSIX shared memory
+
+(allow file-read-data (regex "^/dev/random\$"))
+(allow file-read-data file-write-data (regex "^/dev/console\$")) ; Needed for syslog early in the boot process
+(allow file-read-data (regex "^/dev/autofs_nowait\$")) ; Used by CF to circumvent automount triggers
+
+; Allow us to read and write our socket
+(allow file-read* file-write* (regex "^/private/var/run/mDNSResponder\$"))
+
+; Allow us to read system version, settings, and other miscellaneous necessary file system accesses
+(allow file-read-data (regex "^/usr/sbin(/mDNSResponder)?\$")) ; Needed for CFCopyVersionDictionary()
+(allow file-read-data (regex "^/usr/share/icu/.*\$"))
+(allow file-read-data (regex "^/usr/share/zoneinfo/.*\$"))
+(allow file-read-data (regex "^/System/Library/CoreServices/SystemVersion.*\$"))
+(allow file-read-data (regex "^/Library/Preferences/(ByHost/)?\.GlobalPreferences.*\.plist\$"))
+(allow file-read-data (regex "^/Library/Preferences/com\.apple\.security.*\.plist\$"))
+(allow file-read-data (regex "^/Library/Preferences/com\.apple\.crypto\.plist\$"))
+(allow file-read-data (regex "^/Library/Security/Trust Settings/Admin\.plist\$"))
+(allow file-read-data (regex "^/System/Library/Preferences/com\.apple\.security.*\.plist\$"))
+(allow file-read-data (regex "^/System/Library/Preferences/com\.apple\.crypto\.plist\$"))
+
+; Allow access to System Keychain
+(allow file-read-data (regex "^/System/Library/Security\$"))
+(allow file-read-data (regex "^/System/Library/Keychains/.*\$"))
+(allow file-read-data (regex "^/Library/Keychains/System\.keychain\$"))
+; Our Module Directory Services cache
+(allow file-read-data (regex "^/private/var/tmp/mds/"))
+(allow file-read* file-write* (regex "^/private/var/tmp/mds/[0-9]+(/|\$)"))
+
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 00AD62BB032D7A0C0CCA2C71 /* Build More */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 03067D860C849CC30022BE1F /* PBXTargetDependency */,
+ D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */,
+ D284BF2E0ADD81600027CCDF /* PBXTargetDependency */,
+ D284BF300ADD81630027CCDF /* PBXTargetDependency */,
+ D284BF260ADD814F0027CCDF /* PBXTargetDependency */,
+ D284BF2A0ADD81530027CCDF /* PBXTargetDependency */,
+ FFD41DDB0664169900F0C438 /* PBXTargetDependency */,
+ );
+ name = "Build More";
+ productName = "Build All";
+ };
+ 03067D640C83A3700022BE1F /* Build Some */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 03067D680C83A3830022BE1F /* PBXTargetDependency */,
+ 03067D6A0C83A3890022BE1F /* PBXTargetDependency */,
+ 03067D6C0C83A3920022BE1F /* PBXTargetDependency */,
+ 03067D6E0C83A39C0022BE1F /* PBXTargetDependency */,
+ );
+ name = "Build Some";
+ productName = "Build Some";
+ };
+ FFA572650AF190F10055A0F1 /* SystemLibraries */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibraries" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FFA572690AF190FF0055A0F1 /* PBXTargetDependency */,
+ FFA5726B0AF191010055A0F1 /* PBXTargetDependency */,
+ FFA5726D0AF191020055A0F1 /* PBXTargetDependency */,
+ );
+ name = SystemLibraries;
+ productName = SystemLibraries;
+ };
+ FFB7657B0AEED96B00583A2C /* Build All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FFB7657D0AEED97F00583A2C /* PBXTargetDependency */,
+ FFA572710AF191230055A0F1 /* PBXTargetDependency */,
+ );
+ name = "Build All";
+ productName = "Build All";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; };
+ 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Server, Client, ); }; };
+ 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; };
+ 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+ 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+ 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+ 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+ 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+ 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+ 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+ 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202520C56C36500DDFD48 /* libpfkey.h */; };
+ 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; };
+ 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */; };
+ 2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
+ 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
+ 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; };
+ 2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 2E96A5270C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+ 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+ 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+ 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+ 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+ 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+ 2EDC5E730C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
+ 2EDC5E740C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
+ 2EDC5E750C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
+ 4A8202650C56C4C900DDFD48 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; };
+ 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */; };
+ D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; };
+ D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
+ D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; };
+ D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+ D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+ D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+ D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+ D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+ D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+ D284BE630ADD80740027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+ D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ D284BE680ADD80740027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF485D5105632E0000130380 /* mDNSResponder.8 */; };
+ D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; };
+ D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
+ D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */; };
+ D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE65002B63B93000001D1 /* mDNSDebug.h */; };
+ D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */; };
+ D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; };
+ D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ D284BE800ADD80800027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+ D284BE810ADD80800027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+ D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+ D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+ D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+ D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+ D284BE8B0ADD80800027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+ D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ D284BE900ADD80800027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BE9A0ADD808B0027CCDF /* SamplemDNSClient.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */; };
+ D284BE9C0ADD808B0027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BE9F0ADD808B0027CCDF /* mDNS.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */; };
+ D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF1C919F07021E3F001048AB /* dns-sd.c */; };
+ D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF1C919D07021D77001048AB /* dns-sd.1 */; };
+ D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44B0662DD1100335AB3 /* JNISupport.c */; };
+ D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB2CC4680662DFF500335AB3 /* JavaVM.framework */; };
+ D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+ D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF25794606C9A8BF00376F7B /* dnsextd.c */; };
+ D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
+ D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+ D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */; settings = {COMPILER_FLAGS = "-Wno-error"; }; };
+ D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */; };
+ D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */; };
+ D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */; };
+ D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFFB0DB407B43D2700B88D48 /* Foundation.framework */; };
+ D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2407B4464B00CE10E5 /* remove_idle.tiff */; };
+ D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2507B4464B00CE10E5 /* add_pressed.tiff */; };
+ D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */; };
+ D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2707B4464B00CE10E5 /* add_idle.tiff */; };
+ D284BEF30ADD80B00027CCDF /* success.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2807B4464B00CE10E5 /* success.tiff */; };
+ D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */; };
+ D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2A07B4464B00CE10E5 /* failure.tiff */; };
+ D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3207B4466900CE10E5 /* BonjourPref.icns */; };
+ D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3307B4466900CE10E5 /* BonjourPref.tiff */; };
+ D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */; };
+ D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */; };
+ D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF08480607CEB8E800AE6769 /* inprogress.tiff */; };
+ D284BEFC0ADD80B00027CCDF /* installtool in Resources */ = {isa = PBXBuildFile; fileRef = FF354EB108516C63007C00E1 /* installtool */; };
+ D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */; };
+ D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */; };
+ D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */; };
+ D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF2609FA07B4433800CE10E5 /* Cocoa.framework */; };
+ D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; };
+ D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284C04E0ADD95D30027CCDF /* Info-PreferencePane.plist in Resources */ = {isa = PBXBuildFile; fileRef = D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */; };
+ DB2CC4560662DE4500335AB3 /* BaseListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4430662DD1100335AB3 /* BaseListener.java */; };
+ DB2CC4570662DE4600335AB3 /* BrowseListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4440662DD1100335AB3 /* BrowseListener.java */; };
+ DB2CC4580662DE4700335AB3 /* DNSRecord.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4450662DD1100335AB3 /* DNSRecord.java */; };
+ DB2CC4590662DE4700335AB3 /* DNSSD.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4460662DD1100335AB3 /* DNSSD.java */; };
+ DB2CC45A0662DE4800335AB3 /* DNSSDException.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4470662DD1100335AB3 /* DNSSDException.java */; };
+ DB2CC45B0662DE4900335AB3 /* DNSSDRegistration.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */; };
+ DB2CC45C0662DE4900335AB3 /* DNSSDService.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4490662DD1100335AB3 /* DNSSDService.java */; };
+ DB2CC45D0662DE4A00335AB3 /* DomainListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44A0662DD1100335AB3 /* DomainListener.java */; };
+ DB2CC45E0662DE4B00335AB3 /* QueryListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44C0662DD1100335AB3 /* QueryListener.java */; };
+ DB2CC45F0662DE4C00335AB3 /* RegisterListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44D0662DD1100335AB3 /* RegisterListener.java */; };
+ DB2CC4600662DE4C00335AB3 /* ResolveListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44E0662DD1100335AB3 /* ResolveListener.java */; };
+ DB2CC4610662DE4D00335AB3 /* TXTRecord.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44F0662DD1100335AB3 /* TXTRecord.java */; };
+ FF2C5FB10A48B8680066DA11 /* DNSSDRecordRegistrar.java in Sources */ = {isa = PBXBuildFile; fileRef = FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */; };
+ FF2C5FB30A48B86E0066DA11 /* RegisterRecordListener.java in Sources */ = {isa = PBXBuildFile; fileRef = FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */; };
+ FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ FFA572610AF190940055A0F1 /* DNSServiceDiscovery.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */; };
+ FFA572640AF190C80055A0F1 /* dns_sd.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; };
+ FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFFF8F800C3307AC00722979 /* dnsextd.conf */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+ D284BF750ADD850C0027CCDF /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.proxy.script;
+ fileType = sourcecode.yacc;
+ isEditable = 1;
+ outputFiles = (
+ "$(DERIVED_FILE_DIR)/dnsextd_parser.h",
+ "$(DERIVED_FILE_DIR)/dnsextd_parser.c",
+ );
+ script = "/usr/bin/bison -o ${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c -d ${INPUT_FILE_PATH}";
+ };
+ D284BFB80ADD8E510027CCDF /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.proxy.script;
+ fileType = sourcecode.lex;
+ isEditable = 1;
+ outputFiles = (
+ "$(DERIVED_FILE_DIR)/dnsextd_lexer.c",
+ );
+ script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}";
+ };
+/* End PBXBuildRule section */
+
+/* Begin PBXContainerItemProxy section */
+ 03067D670C83A3830022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BE500ADD80740027CCDF /* mDNSResponder */;
+ remoteInfo = mDNSResponder;
+ };
+ 03067D690C83A3890022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BE750ADD80800027CCDF /* mDNSResponder debug */;
+ remoteInfo = "mDNSResponder debug";
+ };
+ 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEA50ADD80920027CCDF /* dns-sd tool */;
+ remoteInfo = "dns-sd tool";
+ };
+ 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */;
+ remoteInfo = mDNSResponderHelper;
+ };
+ 03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 03067D640C83A3700022BE1F /* Build Some */;
+ remoteInfo = "Build Some";
+ };
+ D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DB2CC4530662DD6800335AB3;
+ remoteInfo = dns_sd.jar;
+ };
+ D284BEB40ADD809A0027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DB2CC4530662DD6800335AB3;
+ remoteInfo = dns_sd.jar;
+ };
+ D284BF250ADD814F0027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BE970ADD808B0027CCDF;
+ remoteInfo = "mDNS command-line tool";
+ };
+ D284BF290ADD81530027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEB20ADD809A0027CCDF;
+ remoteInfo = libjdns_sd.jnilib;
+ };
+ D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEBF0ADD80A20027CCDF;
+ remoteInfo = dnsextd;
+ };
+ D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEDB0ADD80A70027CCDF;
+ remoteInfo = ddnswriteconfig;
+ };
+ D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEEA0ADD80B00027CCDF;
+ remoteInfo = PreferencePane;
+ };
+ FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FFB765830AEED9C700583A2C;
+ remoteInfo = libdns_sd;
+ };
+ FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FFA572300AF18F1C0055A0F1;
+ remoteInfo = "libdns_sd debug";
+ };
+ FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FFA5723C0AF18F450055A0F1;
+ remoteInfo = "libdns_sd profile";
+ };
+ FFA572700AF191230055A0F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FFA572650AF190F10055A0F1;
+ remoteInfo = SystemLibraries;
+ };
+ FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 00AD62BB032D7A0C0CCA2C71;
+ remoteInfo = "Build Main";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 4AAE0C5A0C68E6EC003882A5 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ D284BE6A0ADD80740027CCDF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ D284BE9E0ADD808B0027CCDF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ D284BE9F0ADD808B0027CCDF /* mDNS.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ D284BEAB0ADD80920027CCDF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ D284BED40ADD80A20027CCDF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FF93944E0AF193B900C5D655 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/include;
+ dstSubfolderSpec = 0;
+ files = (
+ FFA572640AF190C80055A0F1 /* dns_sd.h in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FFA572500AF190070055A0F1 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/include/DNSServiceDiscovery;
+ dstSubfolderSpec = 0;
+ files = (
+ FFA572610AF190940055A0F1 /* DNSServiceDiscovery.h in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FFFF8F770C32F0FD00722979 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc;
+ dstSubfolderSpec = 0;
+ files = (
+ FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mDNSMacOSX.h; sourceTree = "<group>"; };
+ 00CA213D02786FC30CCA2C71 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
+ 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+ 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.mig; path = helpermsg.defs; sourceTree = "<group>"; };
+ 2E0405F00C31955500F13B59 /* mDNSResponderHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponderHelper; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2E0405F40C3195F700F13B59 /* helper.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = helper.c; sourceTree = "<group>"; };
+ 2E0406140C3197CB00F13B59 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
+ 2E0406CA0C31E9AD00F13B59 /* helper-main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "helper-main.c"; sourceTree = "<group>"; };
+ 2E35528F0C3A95C100CA1CB7 /* helper-error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-error.h"; sourceTree = "<group>"; };
+ 2E8165F60C59835F00485EB2 /* libipsec.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipsec.dylib; path = /usr/lib/libipsec.dylib; sourceTree = "<absolute>"; };
+ 2E96A5250C39BE480087C4D2 /* helper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = helper.h; sourceTree = "<group>"; };
+ 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "helper-stubs.c"; sourceTree = "<group>"; };
+ 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "helpermsg-types.h"; sourceTree = "<group>"; };
+ 2EDC5E720C39EA640092701B /* helper-server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-server.h"; sourceTree = "<group>"; };
+ 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsec_strerror.h; sourceTree = "<group>"; };
+ 4A8202520C56C36500DDFD48 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libpfkey.h; sourceTree = "<group>"; };
+ 4A8202530C56C36600DDFD48 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pfkey.c; sourceTree = "<group>"; };
+ 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponderHelper.8; sourceTree = SOURCE_ROOT; };
+ 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSEmbeddedAPI.h; path = ../mDNSCore/mDNSEmbeddedAPI.h; sourceTree = "<group>"; };
+ 654BE65002B63B93000001D1 /* mDNSDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSDebug.h; path = ../mDNSCore/mDNSDebug.h; sourceTree = "<group>"; };
+ 65713D46025A293200000109 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
+ 6575FBE9022EAF5A00000109 /* mDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = mDNS.c; path = ../mDNSCore/mDNS.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ 6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscoveryDefines.h; sourceTree = "<group>"; };
+ 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryReply.defs; sourceTree = "<group>"; };
+ 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryRequest.defs; sourceTree = "<group>"; };
+ 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = SamplemDNSClient.c; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 0; };
+ 7F18A9F60587CEF6001880B3 /* DNSCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSCommon.c; path = ../mDNSCore/DNSCommon.c; sourceTree = SOURCE_ROOT; };
+ 7F18A9F70587CEF6001880B3 /* uDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uDNS.c; path = ../mDNSCore/uDNS.c; sourceTree = SOURCE_ROOT; };
+ 7F461DB5062DBF2900672BF3 /* DNSDigest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSDigest.c; path = ../mDNSCore/DNSDigest.c; sourceTree = SOURCE_ROOT; };
+ 7F869685066EE02400D2A2DC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
+ 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LegacyNATTraversal.c; sourceTree = SOURCE_ROOT; };
+ D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BE950ADD80800027CCDF /* mDNSResponder.debug */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder.debug; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BEA30ADD808B0027CCDF /* mDNS */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNS; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BEB00ADD80920027CCDF /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjdns_sd.jnilib; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BED90ADD80A20027CCDF /* dnsextd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsextd; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BEE80ADD80A70027CCDF /* ddnswriteconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ddnswriteconfig; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Bonjour.prefPane; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = "Info-PreferencePane.plist"; path = "PreferencePane/Info-PreferencePane.plist"; sourceTree = "<group>"; };
+ DB2CC4430662DD1100335AB3 /* BaseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BaseListener.java; path = ../mDNSShared/Java/BaseListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4440662DD1100335AB3 /* BrowseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BrowseListener.java; path = ../mDNSShared/Java/BrowseListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4450662DD1100335AB3 /* DNSRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSRecord.java; path = ../mDNSShared/Java/DNSRecord.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4460662DD1100335AB3 /* DNSSD.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSD.java; path = ../mDNSShared/Java/DNSSD.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4470662DD1100335AB3 /* DNSSDException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDException.java; path = ../mDNSShared/Java/DNSSDException.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRegistration.java; path = ../mDNSShared/Java/DNSSDRegistration.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4490662DD1100335AB3 /* DNSSDService.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDService.java; path = ../mDNSShared/Java/DNSSDService.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44A0662DD1100335AB3 /* DomainListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DomainListener.java; path = ../mDNSShared/Java/DomainListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44B0662DD1100335AB3 /* JNISupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = JNISupport.c; path = ../mDNSShared/Java/JNISupport.c; sourceTree = SOURCE_ROOT; };
+ DB2CC44C0662DD1100335AB3 /* QueryListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = QueryListener.java; path = ../mDNSShared/Java/QueryListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44D0662DD1100335AB3 /* RegisterListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterListener.java; path = ../mDNSShared/Java/RegisterListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44E0662DD1100335AB3 /* ResolveListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = ResolveListener.java; path = ../mDNSShared/Java/ResolveListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44F0662DD1100335AB3 /* TXTRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = TXTRecord.java; path = ../mDNSShared/Java/TXTRecord.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4680662DFF500335AB3 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = "<absolute>"; };
+ DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSDebug.c; path = ../mDNSShared/mDNSDebug.c; sourceTree = SOURCE_ROOT; };
+ DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GenLinkedList.c; path = ../mDNSShared/GenLinkedList.c; sourceTree = SOURCE_ROOT; };
+ F525E72804AA167501F1CF4D /* uds_daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon.c; path = ../mDNSShared/uds_daemon.c; sourceTree = SOURCE_ROOT; };
+ F5E11B5A04A28126019798ED /* dnssd_ipc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_ipc.c; path = ../mDNSShared/dnssd_ipc.c; sourceTree = SOURCE_ROOT; };
+ F5E11B5B04A28126019798ED /* dnssd_ipc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssd_ipc.h; path = ../mDNSShared/dnssd_ipc.h; sourceTree = SOURCE_ROOT; };
+ FF08480607CEB8E800AE6769 /* inprogress.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = inprogress.tiff; path = PreferencePane/Artwork/inprogress.tiff; sourceTree = SOURCE_ROOT; };
+ FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = mDNS.1; path = ../mDNSShared/mDNS.1; sourceTree = SOURCE_ROOT; };
+ FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; name = dnsextd_lexer.l; path = ../mDNSShared/dnsextd_lexer.l; sourceTree = SOURCE_ROOT; };
+ FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; name = dnsextd_parser.y; path = ../mDNSShared/dnsextd_parser.y; sourceTree = SOURCE_ROOT; };
+ FF1C919D07021D77001048AB /* dns-sd.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = "dns-sd.1"; path = "../mDNSShared/dns-sd.1"; sourceTree = SOURCE_ROOT; };
+ FF1C919F07021E3F001048AB /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dns-sd.c"; path = "../Clients/dns-sd.c"; sourceTree = SOURCE_ROOT; };
+ FF25794606C9A8BF00376F7B /* dnsextd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsextd.c; path = ../mDNSShared/dnsextd.c; sourceTree = SOURCE_ROOT; };
+ FF2609FA07B4433800CE10E5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = /System/Library/Frameworks/PreferencePanes.framework; sourceTree = "<absolute>"; };
+ FF260A2407B4464B00CE10E5 /* remove_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_idle.tiff; path = PreferencePane/Artwork/remove_idle.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2507B4464B00CE10E5 /* add_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_pressed.tiff; path = PreferencePane/Artwork/add_pressed.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_disabled.tiff; path = PreferencePane/Artwork/remove_disabled.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2707B4464B00CE10E5 /* add_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_idle.tiff; path = PreferencePane/Artwork/add_idle.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2807B4464B00CE10E5 /* success.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = success.tiff; path = PreferencePane/Artwork/success.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_pressed.tiff; path = PreferencePane/Artwork/remove_pressed.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2A07B4464B00CE10E5 /* failure.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = failure.tiff; path = PreferencePane/Artwork/failure.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A3207B4466900CE10E5 /* BonjourPref.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = BonjourPref.icns; path = PreferencePane/BonjourPref.icns; sourceTree = SOURCE_ROOT; };
+ FF260A3307B4466900CE10E5 /* BonjourPref.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BonjourPref.tiff; path = PreferencePane/BonjourPref.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A4907B4475600CE10E5 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib; sourceTree = SOURCE_ROOT; };
+ FF260A4C07B4477F00CE10E5 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = PreferencePane/English.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
+ FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRecordRegistrar.java; path = ../mDNSShared/Java/DNSSDRecordRegistrar.java; sourceTree = SOURCE_ROOT; };
+ FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterRecordListener.java; path = ../mDNSShared/Java/RegisterRecordListener.java; sourceTree = SOURCE_ROOT; };
+ FF354EB108516C63007C00E1 /* installtool */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = installtool; path = PreferencePane/installtool; sourceTree = SOURCE_ROOT; };
+ FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; };
+ FF85880B0BD599F40080D89F /* mDNSResponder.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponder.sb; sourceTree = SOURCE_ROOT; };
+ FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_debug.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_profile.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSServiceDiscovery.c; sourceTree = "<group>"; };
+ FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscovery.h; sourceTree = "<group>"; };
+ FFA572630AF190C20055A0F1 /* dns_sd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd.h; path = ../mDNSShared/dns_sd.h; sourceTree = SOURCE_ROOT; };
+ FFB765840AEED9C700583A2C /* libdns_sd.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ FFCB6D73075D539900B8AF62 /* PlatformCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PlatformCommon.c; path = ../mDNSShared/PlatformCommon.c; sourceTree = SOURCE_ROOT; };
+ FFD41DDA0664157900F0C438 /* dns_sd.jar */ = {isa = PBXFileReference; explicitFileType = archive.jar; includeInIndex = 0; path = dns_sd.jar; sourceTree = BUILT_PRODUCTS_DIR; };
+ FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigurationAuthority.h; path = PreferencePane/ConfigurationAuthority.h; sourceTree = SOURCE_ROOT; };
+ FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSServiceDiscoveryPref.h; path = PreferencePane/DNSServiceDiscoveryPref.h; sourceTree = SOURCE_ROOT; };
+ FFE6935407C2CABD00283007 /* PrivilegedOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrivilegedOperations.h; path = PreferencePane/PrivilegedOperations.h; sourceTree = SOURCE_ROOT; };
+ FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.8; path = ../mDNSShared/dnsextd.8; sourceTree = SOURCE_ROOT; };
+ FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientlib.c; path = ../mDNSShared/dnssd_clientlib.c; sourceTree = SOURCE_ROOT; };
+ FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientstub.c; path = ../mDNSShared/dnssd_clientstub.c; sourceTree = SOURCE_ROOT; };
+ FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceDiscoveryPref.m; sourceTree = "<group>"; };
+ FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = PrivilegedOperations.c; sourceTree = "<group>"; };
+ FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConfigurationAuthority.c; sourceTree = "<group>"; };
+ FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ddnswriteconfig.m; sourceTree = "<group>"; };
+ FFFB0DB407B43D2700B88D48 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ FFFF8F800C3307AC00722979 /* dnsextd.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.conf; path = ../mDNSShared/dnsextd.conf; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2E0405EE0C31955500F13B59 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */,
+ 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */,
+ 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */,
+ 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */,
+ 2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE640ADD80740027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */,
+ D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
+ D284BE680ADD80740027CCDF /* Security.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE8C0ADD80800027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */,
+ D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */,
+ D284BE900ADD80800027CCDF /* Security.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE9B0ADD808B0027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE9C0ADD808B0027CCDF /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEA90ADD80920027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEB80ADD809A0027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BECE0ADD80A20027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */,
+ D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */,
+ D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */,
+ 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEDF0ADD80A70027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */,
+ D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */,
+ D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BF010ADD80B00027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */,
+ D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */,
+ D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */,
+ D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4520662DD6800335AB3 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA572360AF18F1C0055A0F1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA572420AF18F450055A0F1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFB765820AEED9C700583A2C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* mDNSResponder */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */,
+ 6575FC1F022EB78C00000109 /* Command-Line Clients */,
+ 6575FBFE022EAFA800000109 /* MIG files */,
+ DB2CC4420662DCE500335AB3 /* Java Support */,
+ FFFB0DA407B43BED00B88D48 /* PreferencePane */,
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+ 19C28FBDFE9D53C911CA2CBB /* Products */,
+ );
+ name = mDNSResponder;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
+ isa = PBXGroup;
+ children = (
+ 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */,
+ 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */,
+ 2E35528F0C3A95C100CA1CB7 /* helper-error.h */,
+ 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */,
+ 2EDC5E720C39EA640092701B /* helper-server.h */,
+ 2E96A5250C39BE480087C4D2 /* helper.h */,
+ 2E0405F40C3195F700F13B59 /* helper.c */,
+ 2E0406CA0C31E9AD00F13B59 /* helper-main.c */,
+ 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */,
+ 4A8202520C56C36500DDFD48 /* libpfkey.h */,
+ 4A8202530C56C36600DDFD48 /* pfkey.c */,
+ 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */,
+ 7F461DB5062DBF2900672BF3 /* DNSDigest.c */,
+ F525E72804AA167501F1CF4D /* uds_daemon.c */,
+ F5E11B5A04A28126019798ED /* dnssd_ipc.c */,
+ F5E11B5B04A28126019798ED /* dnssd_ipc.h */,
+ 6575FBEC022EAF7200000109 /* daemon.c */,
+ 6575FBE9022EAF5A00000109 /* mDNS.c */,
+ 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */,
+ 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */,
+ 654BE65002B63B93000001D1 /* mDNSDebug.h */,
+ DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */,
+ 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */,
+ DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */,
+ FFCB6D73075D539900B8AF62 /* PlatformCommon.c */,
+ FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */,
+ FF1C919D07021D77001048AB /* dns-sd.1 */,
+ FF485D5105632E0000130380 /* mDNSResponder.8 */,
+ FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */,
+ FFFF8F800C3307AC00722979 /* dnsextd.conf */,
+ FF85880B0BD599F40080D89F /* mDNSResponder.sb */,
+ 7F18A9F60587CEF6001880B3 /* DNSCommon.c */,
+ 7F18A9F70587CEF6001880B3 /* uDNS.c */,
+ FF25794606C9A8BF00376F7B /* dnsextd.c */,
+ FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */,
+ FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */,
+ FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */,
+ FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */,
+ FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */,
+ FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */,
+ FFA572630AF190C20055A0F1 /* dns_sd.h */,
+ );
+ name = "mDNS Server Sources";
+ sourceTree = "<group>";
+ };
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 2E8165F60C59835F00485EB2 /* libipsec.dylib */,
+ 65713D46025A293200000109 /* SystemConfiguration.framework */,
+ 2E0406140C3197CB00F13B59 /* libbsm.dylib */,
+ 7F869685066EE02400D2A2DC /* Security.framework */,
+ FFFB0DB407B43D2700B88D48 /* Foundation.framework */,
+ 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */,
+ 00CA213D02786FC30CCA2C71 /* IOKit.framework */,
+ DB2CC4680662DFF500335AB3 /* JavaVM.framework */,
+ FF2609FA07B4433800CE10E5 /* Cocoa.framework */,
+ FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 19C28FBDFE9D53C911CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */,
+ FFD41DDA0664157900F0C438 /* dns_sd.jar */,
+ D284BE730ADD80740027CCDF /* mDNSResponder */,
+ D284BE950ADD80800027CCDF /* mDNSResponder.debug */,
+ D284BEA30ADD808B0027CCDF /* mDNS */,
+ D284BEB00ADD80920027CCDF /* dns-sd */,
+ D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */,
+ D284BED90ADD80A20027CCDF /* dnsextd */,
+ D284BEE80ADD80A70027CCDF /* ddnswriteconfig */,
+ D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */,
+ FFB765840AEED9C700583A2C /* libdns_sd.a */,
+ FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */,
+ FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */,
+ 2E0405F00C31955500F13B59 /* mDNSResponderHelper */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 6575FBFE022EAFA800000109 /* MIG files */ = {
+ isa = PBXGroup;
+ children = (
+ 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */,
+ 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */,
+ 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */,
+ 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */,
+ );
+ name = "MIG files";
+ sourceTree = "<group>";
+ };
+ 6575FC1F022EB78C00000109 /* Command-Line Clients */ = {
+ isa = PBXGroup;
+ children = (
+ 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */,
+ FF1C919F07021E3F001048AB /* dns-sd.c */,
+ );
+ name = "Command-Line Clients";
+ sourceTree = "<group>";
+ };
+ DB2CC4420662DCE500335AB3 /* Java Support */ = {
+ isa = PBXGroup;
+ children = (
+ DB2CC4430662DD1100335AB3 /* BaseListener.java */,
+ DB2CC4440662DD1100335AB3 /* BrowseListener.java */,
+ DB2CC4450662DD1100335AB3 /* DNSRecord.java */,
+ DB2CC4460662DD1100335AB3 /* DNSSD.java */,
+ DB2CC4470662DD1100335AB3 /* DNSSDException.java */,
+ DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */,
+ DB2CC4490662DD1100335AB3 /* DNSSDService.java */,
+ DB2CC44A0662DD1100335AB3 /* DomainListener.java */,
+ DB2CC44B0662DD1100335AB3 /* JNISupport.c */,
+ DB2CC44C0662DD1100335AB3 /* QueryListener.java */,
+ DB2CC44D0662DD1100335AB3 /* RegisterListener.java */,
+ DB2CC44E0662DD1100335AB3 /* ResolveListener.java */,
+ DB2CC44F0662DD1100335AB3 /* TXTRecord.java */,
+ FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */,
+ FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */,
+ );
+ name = "Java Support";
+ sourceTree = "<group>";
+ };
+ FF260A2307B4463400CE10E5 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ FF260A2407B4464B00CE10E5 /* remove_idle.tiff */,
+ FF260A2507B4464B00CE10E5 /* add_pressed.tiff */,
+ FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */,
+ FF260A2707B4464B00CE10E5 /* add_idle.tiff */,
+ FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */,
+ FF260A2807B4464B00CE10E5 /* success.tiff */,
+ FF08480607CEB8E800AE6769 /* inprogress.tiff */,
+ FF260A2A07B4464B00CE10E5 /* failure.tiff */,
+ FF260A3207B4466900CE10E5 /* BonjourPref.icns */,
+ FF260A3307B4466900CE10E5 /* BonjourPref.tiff */,
+ FF354EB108516C63007C00E1 /* installtool */,
+ FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */,
+ FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ FFFB0DA407B43BED00B88D48 /* PreferencePane */ = {
+ isa = PBXGroup;
+ children = (
+ FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */,
+ FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */,
+ FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */,
+ FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */,
+ FFE6935407C2CABD00283007 /* PrivilegedOperations.h */,
+ FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */,
+ FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */,
+ FF260A2307B4463400CE10E5 /* Resources */,
+ );
+ path = PreferencePane;
+ sourceTree = SOURCE_ROOT;
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 2EC8F8ED0C39CCCA003C9C48 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */,
+ 2EDC5E730C39EA640092701B /* helper-server.h in Headers */,
+ 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */,
+ 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+ 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */,
+ 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE520ADD80740027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */,
+ D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */,
+ 2E96A5260C39BE480087C4D2 /* helper.h in Headers */,
+ 2EDC5E750C39EA640092701B /* helper-server.h in Headers */,
+ 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */,
+ 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE770ADD80800027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */,
+ D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */,
+ D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */,
+ D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */,
+ D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */,
+ 2E96A5270C39BE480087C4D2 /* helper.h in Headers */,
+ 2EDC5E740C39EA640092701B /* helper-server.h in Headers */,
+ 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */,
+ 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE980ADD808B0027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEA60ADD80920027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEB50ADD809A0027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEC20ADD80A20027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */,
+ 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEDC0ADD80A70027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEED0ADD80B00027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA572310AF18F1C0055A0F1 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA5723D0AF18F450055A0F1 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFB765800AEED9C700583A2C /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXJavaArchiveBuildPhase section */
+ DB2CC4510662DD6800335AB3 /* JavaArchive */ = {
+ isa = PBXJavaArchiveBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXJavaArchiveBuildPhase section */
+
+/* Begin PBXLibraryTarget section */
+ DB2CC4530662DD6800335AB3 /* dns_sd.jar */ = {
+ isa = PBXLibraryTarget;
+ buildConfigurationList = D284BE1C0ADD78180027CCDF /* Build configuration list for PBXLibraryTarget "dns_sd.jar" */;
+ buildPhases = (
+ DB2CC4500662DD6800335AB3 /* Sources */,
+ DB2CC4510662DD6800335AB3 /* JavaArchive */,
+ DB2CC4520662DD6800335AB3 /* Frameworks */,
+ DB2CC4550662DE1700335AB3 /* ShellScript */,
+ FFD41DDD06641B4200F0C438 /* ShellScript */,
+ );
+ comments = "Multiplatform .jar file that implements Java interface to DNS-SD";
+ dependencies = (
+ );
+ name = dns_sd.jar;
+ productInstallPath = /System/Library/Java/Extensions;
+ productName = dns_sd.jar;
+ productReference = FFD41DDA0664157900F0C438 /* dns_sd.jar */;
+ };
+/* End PBXLibraryTarget section */
+
+/* Begin PBXNativeTarget section */
+ 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */;
+ buildPhases = (
+ 2EC8F8ED0C39CCCA003C9C48 /* Headers */,
+ 2E0405ED0C31955500F13B59 /* Sources */,
+ 2E0405EE0C31955500F13B59 /* Frameworks */,
+ 4AAE0C5A0C68E6EC003882A5 /* CopyFiles */,
+ FF045B6A0C7E4AA600448140 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mDNSResponderHelper;
+ productName = mDNSResponderHelper;
+ productReference = 2E0405F00C31955500F13B59 /* mDNSResponderHelper */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BE500ADD80740027CCDF /* mDNSResponder */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */;
+ buildPhases = (
+ D284BE510ADD80740027CCDF /* ShellScript */,
+ D284BE520ADD80740027CCDF /* Headers */,
+ D284BE550ADD80740027CCDF /* Sources */,
+ D284BE640ADD80740027CCDF /* Frameworks */,
+ D284BE690ADD80740027CCDF /* Rez */,
+ D284BE6A0ADD80740027CCDF /* CopyFiles */,
+ D284BE6C0ADD80740027CCDF /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mDNSResponder;
+ productInstallPath = "${HOME}/bin";
+ productName = mDNSResponder;
+ productReference = D284BE730ADD80740027CCDF /* mDNSResponder */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BE750ADD80800027CCDF /* mDNSResponder debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */;
+ buildPhases = (
+ D284BE760ADD80800027CCDF /* ShellScript */,
+ D284BE770ADD80800027CCDF /* Headers */,
+ D284BE7D0ADD80800027CCDF /* Sources */,
+ D284BE8C0ADD80800027CCDF /* Frameworks */,
+ D284BE910ADD80800027CCDF /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "mDNSResponder debug";
+ productName = mDNSResponder;
+ productReference = D284BE950ADD80800027CCDF /* mDNSResponder.debug */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BE970ADD808B0027CCDF /* mDNS tool */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BEA00ADD808B0027CCDF /* Build configuration list for PBXNativeTarget "mDNS tool" */;
+ buildPhases = (
+ D284BE980ADD808B0027CCDF /* Headers */,
+ D284BE990ADD808B0027CCDF /* Sources */,
+ D284BE9B0ADD808B0027CCDF /* Frameworks */,
+ D284BE9D0ADD808B0027CCDF /* Rez */,
+ D284BE9E0ADD808B0027CCDF /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "mDNS tool";
+ productInstallPath = /usr/bin;
+ productName = "mDNS command-line tool";
+ productReference = D284BEA30ADD808B0027CCDF /* mDNS */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BEA50ADD80920027CCDF /* dns-sd tool */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */;
+ buildPhases = (
+ D284BEA60ADD80920027CCDF /* Headers */,
+ D284BEA70ADD80920027CCDF /* Sources */,
+ D284BEA90ADD80920027CCDF /* Frameworks */,
+ D284BEAA0ADD80920027CCDF /* Rez */,
+ D284BEAB0ADD80920027CCDF /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "dns-sd tool";
+ productInstallPath = /usr/bin;
+ productName = "dns-sd command-line tool";
+ productReference = D284BEB00ADD80920027CCDF /* dns-sd */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */;
+ buildPhases = (
+ D284BEB50ADD809A0027CCDF /* Headers */,
+ D284BEB60ADD809A0027CCDF /* Sources */,
+ D284BEB80ADD809A0027CCDF /* Frameworks */,
+ D284BEBA0ADD809A0027CCDF /* Rez */,
+ );
+ buildRules = (
+ );
+ comments = "Platform-specific JNI library that bridges dns_sd.jar to <dns_sd.h>.";
+ dependencies = (
+ D284BEB30ADD809A0027CCDF /* PBXTargetDependency */,
+ );
+ name = libjdns_sd.jnilib;
+ productInstallPath = /usr/lib/java;
+ productName = libjdns_sd.jnilib;
+ productReference = D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ D284BEBF0ADD80A20027CCDF /* dnsextd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
+ buildPhases = (
+ D284BEC20ADD80A20027CCDF /* Headers */,
+ D284BEC40ADD80A20027CCDF /* Sources */,
+ D284BECE0ADD80A20027CCDF /* Frameworks */,
+ D284BED30ADD80A20027CCDF /* Rez */,
+ D284BED40ADD80A20027CCDF /* CopyFiles */,
+ FFFF8F770C32F0FD00722979 /* CopyFiles */,
+ FF37FAAD0BC581780044A5CF /* ShellScript */,
+ );
+ buildRules = (
+ D284BFB80ADD8E510027CCDF /* PBXBuildRule */,
+ D284BF750ADD850C0027CCDF /* PBXBuildRule */,
+ );
+ dependencies = (
+ );
+ name = dnsextd;
+ productInstallPath = /usr/sbin;
+ productName = mDNSResponder;
+ productReference = D284BED90ADD80A20027CCDF /* dnsextd */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */;
+ buildPhases = (
+ D284BEDC0ADD80A70027CCDF /* Headers */,
+ D284BEDD0ADD80A70027CCDF /* Sources */,
+ D284BEDF0ADD80A70027CCDF /* Frameworks */,
+ D284BEE40ADD80A70027CCDF /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ddnswriteconfig;
+ productInstallPath = "/Library/Application Support/Bonjour";
+ productName = ddnswriteconfig;
+ productReference = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BEEA0ADD80B00027CCDF /* PreferencePane */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */;
+ buildPhases = (
+ D284BEED0ADD80B00027CCDF /* Headers */,
+ D284BEEE0ADD80B00027CCDF /* Resources */,
+ D284BEFD0ADD80B00027CCDF /* Sources */,
+ D284BF010ADD80B00027CCDF /* Frameworks */,
+ D284BF070ADD80B00027CCDF /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = PreferencePane;
+ productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
+ productName = PreferencePane;
+ productReference = D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */;
+ productType = "com.apple.product-type.bundle";
+ };
+ FFA572300AF18F1C0055A0F1 /* libdns_sd debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd debug" */;
+ buildPhases = (
+ FFA572310AF18F1C0055A0F1 /* Headers */,
+ FFA572320AF18F1C0055A0F1 /* Sources */,
+ FFA572360AF18F1C0055A0F1 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "libdns_sd debug";
+ productName = libdns_sd.a;
+ productReference = FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ FFA5723C0AF18F450055A0F1 /* libdns_sd profile */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd profile" */;
+ buildPhases = (
+ FFA5723D0AF18F450055A0F1 /* Headers */,
+ FFA5723E0AF18F450055A0F1 /* Sources */,
+ FFA572420AF18F450055A0F1 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "libdns_sd profile";
+ productName = libdns_sd.a;
+ productReference = FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ FFB765830AEED9C700583A2C /* libdns_sd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd" */;
+ buildPhases = (
+ FFB765800AEED9C700583A2C /* Headers */,
+ FFB765810AEED9C700583A2C /* Sources */,
+ FFB765820AEED9C700583A2C /* Frameworks */,
+ FFA572500AF190070055A0F1 /* CopyFiles */,
+ FF93944E0AF193B900C5D655 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libdns_sd;
+ productName = libdns_sd.a;
+ productReference = FFB765840AEED9C700583A2C /* libdns_sd.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 00AD62BB032D7A0C0CCA2C71 /* Build More */,
+ 03067D640C83A3700022BE1F /* Build Some */,
+ FFB7657B0AEED96B00583A2C /* Build All */,
+ D284BE500ADD80740027CCDF /* mDNSResponder */,
+ D284BE750ADD80800027CCDF /* mDNSResponder debug */,
+ 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */,
+ D284BE970ADD808B0027CCDF /* mDNS tool */,
+ D284BEA50ADD80920027CCDF /* dns-sd tool */,
+ DB2CC4530662DD6800335AB3 /* dns_sd.jar */,
+ D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */,
+ D284BEBF0ADD80A20027CCDF /* dnsextd */,
+ D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */,
+ D284BEEA0ADD80B00027CCDF /* PreferencePane */,
+ FFB765830AEED9C700583A2C /* libdns_sd */,
+ FFA572300AF18F1C0055A0F1 /* libdns_sd debug */,
+ FFA5723C0AF18F450055A0F1 /* libdns_sd profile */,
+ FFA572650AF190F10055A0F1 /* SystemLibraries */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ D284BEEE0ADD80B00027CCDF /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */,
+ D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */,
+ D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */,
+ D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */,
+ D284BEF30ADD80B00027CCDF /* success.tiff in Resources */,
+ D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */,
+ D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */,
+ D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */,
+ D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */,
+ D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */,
+ D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */,
+ D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */,
+ D284BEFC0ADD80B00027CCDF /* installtool in Resources */,
+ D284C04E0ADD95D30027CCDF /* Info-PreferencePane.plist in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ D284BE690ADD80740027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE910ADD80800027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE9D0ADD808B0027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEAA0ADD80920027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEBA0ADD809A0027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BED30ADD80A20027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEE40ADD80A70027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BF070ADD80B00027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ D284BE510ADD80740027CCDF /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc -arch i386 -arch ppc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi\n\nif [ -e /usr/include/sandbox.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > ${CONFIGURATION_TEMP_DIR}/sandbox.h\nfi\n";
+ };
+ D284BE6C0ADD80740027CCDF /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/tcsh;
+ shellScript = "# Install plist to tell launchd to start mDNSResponder\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\n\n# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n\n# Copy Sandbox profile, stripping initial license header to make the file fit in the ~16kB Sandbox profile limit\n(umask 022; mkdir -p -m 0755 ${DSTROOT}/usr/share/sandbox)\n(umask 222; awk '/^\\(version 1\\)$/,EOF' ${SRCROOT}/mDNSResponder.sb > ${DSTROOT}/usr/share/sandbox/mDNSResponder.sb)\n";
+ };
+ D284BE760ADD80800027CCDF /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc -arch i386 -arch ppc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi\n\nif [ -e /usr/include/sandbox.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > ${CONFIGURATION_TEMP_DIR}/sandbox.h\nfi\n";
+ };
+ DB2CC4550662DE1700335AB3 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 12;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "javah -force -J-Xbootclasspath/p:${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/JavaClasses -o ${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService com.apple.dnssd.AppleDNSRecord com.apple.dnssd.AppleRecordRegistrar";
+ };
+ FF045B6A0C7E4AA600448140 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/tcsh;
+ shellScript = "# Install plist to tell launchd how to start mDNSResponderHelper\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\n";
+ };
+ FF37FAAD0BC581780044A5CF /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/tcsh;
+ shellScript = "# Install plist to tell launchd how to start dnsextd\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.dnsextd.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.dnsextd.plist\n";
+ };
+ FFD41DDD06641B4200F0C438 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "rm -f ${CONFIGURATION_BUILD_DIR}/dns_sd";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2E0405ED0C31955500F13B59 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2E0405F50C3195F700F13B59 /* helper.c in Sources */,
+ 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */,
+ 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */,
+ 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE550ADD80740027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */,
+ D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */,
+ D284BE580ADD80740027CCDF /* mDNS.c in Sources */,
+ D284BE590ADD80740027CCDF /* uDNS.c in Sources */,
+ D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */,
+ D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */,
+ D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */,
+ D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */,
+ D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */,
+ D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */,
+ D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */,
+ D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */,
+ D284BE630ADD80740027CCDF /* daemon.c in Sources */,
+ 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */,
+ 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE7D0ADD80800027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */,
+ D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */,
+ D284BE800ADD80800027CCDF /* mDNS.c in Sources */,
+ D284BE810ADD80800027CCDF /* uDNS.c in Sources */,
+ D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */,
+ D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */,
+ D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */,
+ D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */,
+ D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */,
+ D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */,
+ D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */,
+ D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */,
+ D284BE8B0ADD80800027CCDF /* daemon.c in Sources */,
+ 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */,
+ 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE990ADD808B0027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE9A0ADD808B0027CCDF /* SamplemDNSClient.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEA70ADD80920027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEB60ADD809A0027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEC40ADD80A20027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */,
+ D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */,
+ D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */,
+ D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */,
+ D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */,
+ D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */,
+ D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */,
+ D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */,
+ D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */,
+ 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */,
+ 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */,
+ 4A8202650C56C4C900DDFD48 /* pfkey.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEDD0ADD80A70027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEFD0ADD80B00027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */,
+ D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */,
+ D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4500662DD6800335AB3 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DB2CC4560662DE4500335AB3 /* BaseListener.java in Sources */,
+ DB2CC4570662DE4600335AB3 /* BrowseListener.java in Sources */,
+ DB2CC4580662DE4700335AB3 /* DNSRecord.java in Sources */,
+ DB2CC4590662DE4700335AB3 /* DNSSD.java in Sources */,
+ DB2CC45A0662DE4800335AB3 /* DNSSDException.java in Sources */,
+ DB2CC45B0662DE4900335AB3 /* DNSSDRegistration.java in Sources */,
+ DB2CC45C0662DE4900335AB3 /* DNSSDService.java in Sources */,
+ DB2CC45D0662DE4A00335AB3 /* DomainListener.java in Sources */,
+ DB2CC45E0662DE4B00335AB3 /* QueryListener.java in Sources */,
+ DB2CC45F0662DE4C00335AB3 /* RegisterListener.java in Sources */,
+ DB2CC4600662DE4C00335AB3 /* ResolveListener.java in Sources */,
+ DB2CC4610662DE4D00335AB3 /* TXTRecord.java in Sources */,
+ FF2C5FB10A48B8680066DA11 /* DNSSDRecordRegistrar.java in Sources */,
+ FF2C5FB30A48B86E0066DA11 /* RegisterRecordListener.java in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA572320AF18F1C0055A0F1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */,
+ FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */,
+ FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */,
+ FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+ FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA5723E0AF18F450055A0F1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */,
+ FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */,
+ FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */,
+ FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+ FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFB765810AEED9C700583A2C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */,
+ FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */,
+ FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */,
+ FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+ FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 03067D680C83A3830022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BE500ADD80740027CCDF /* mDNSResponder */;
+ targetProxy = 03067D670C83A3830022BE1F /* PBXContainerItemProxy */;
+ };
+ 03067D6A0C83A3890022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BE750ADD80800027CCDF /* mDNSResponder debug */;
+ targetProxy = 03067D690C83A3890022BE1F /* PBXContainerItemProxy */;
+ };
+ 03067D6C0C83A3920022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEA50ADD80920027CCDF /* dns-sd tool */;
+ targetProxy = 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */;
+ };
+ 03067D6E0C83A39C0022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */;
+ targetProxy = 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */;
+ };
+ 03067D860C849CC30022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 03067D640C83A3700022BE1F /* Build Some */;
+ targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */;
+ };
+ D284BEB30ADD809A0027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DB2CC4530662DD6800335AB3 /* dns_sd.jar */;
+ targetProxy = D284BEB40ADD809A0027CCDF /* PBXContainerItemProxy */;
+ };
+ D284BF260ADD814F0027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BE970ADD808B0027CCDF /* mDNS tool */;
+ targetProxy = D284BF250ADD814F0027CCDF /* PBXContainerItemProxy */;
+ };
+ D284BF2A0ADD81530027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */;
+ targetProxy = D284BF290ADD81530027CCDF /* PBXContainerItemProxy */;
+ };
+ D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEBF0ADD80A20027CCDF /* dnsextd */;
+ targetProxy = D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */;
+ };
+ D284BF2E0ADD81600027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */;
+ targetProxy = D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */;
+ };
+ D284BF300ADD81630027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEEA0ADD80B00027CCDF /* PreferencePane */;
+ targetProxy = D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */;
+ };
+ FFA572690AF190FF0055A0F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FFB765830AEED9C700583A2C /* libdns_sd */;
+ targetProxy = FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */;
+ };
+ FFA5726B0AF191010055A0F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FFA572300AF18F1C0055A0F1 /* libdns_sd debug */;
+ targetProxy = FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */;
+ };
+ FFA5726D0AF191020055A0F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FFA5723C0AF18F450055A0F1 /* libdns_sd profile */;
+ targetProxy = FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */;
+ };
+ FFA572710AF191230055A0F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FFA572650AF190F10055A0F1 /* SystemLibraries */;
+ targetProxy = FFA572700AF191230055A0F1 /* PBXContainerItemProxy */;
+ };
+ FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 00AD62BB032D7A0C0CCA2C71 /* Build More */;
+ targetProxy = FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */;
+ };
+ FFD41DDB0664169900F0C438 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DB2CC4530662DD6800335AB3 /* dns_sd.jar */;
+ targetProxy = D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ FF260A4907B4475600CE10E5 /* English */,
+ );
+ name = DNSServiceDiscoveryPref.nib;
+ path = PreferencePane;
+ sourceTree = SOURCE_ROOT;
+ };
+ FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ FF260A4C07B4477F00CE10E5 /* English */,
+ );
+ name = InfoPlist.strings;
+ path = PreferencePane;
+ sourceTree = SOURCE_ROOT;
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 03067D740C83A3CB0022BE1F /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = "Build Some";
+ };
+ name = Development;
+ };
+ 2E0405F20C31955500F13B59 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+ CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
+ HEADER_SEARCH_PATHS = "${CONFIGURATION_TEMP_DIR}";
+ INSTALL_PATH = /usr/sbin;
+ LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt";
+ MACOSX_DEPLOYMENT_TARGET = 10.4;
+ PREBINDING = NO;
+ PRODUCT_NAME = mDNSResponderHelper;
+ };
+ name = Development;
+ };
+ D284BE1D0ADD78180027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ INSTALL_PATH = "${SYSTEM_LIBRARY_DIR}/Java/Extensions";
+ JAVA_ARCHIVE_CLASSES = YES;
+ JAVA_ARCHIVE_COMPRESSION = YES;
+ JAVA_ARCHIVE_TYPE = JAR;
+ JAVA_COMPILER_DEBUGGING_SYMBOLS = NO;
+ JAVA_COMPILER_SOURCE_VERSION = 1.4;
+ JAVA_COMPILER_TARGET_VM_VERSION = 1.4;
+ JAVA_SOURCE_SUBDIR = .;
+ LIBRARY_STYLE = STATIC;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_LIBTOOL_FLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = dns_sd;
+ PURE_JAVA = YES;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ };
+ name = Development;
+ };
+ D284BE290ADD78180027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "Build All";
+ SECTORDER_FLAGS = "";
+ };
+ name = Development;
+ };
+ D284BE2C0ADD78180027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "APPLE_OSX_mDNSResponder=1",
+ "__MigTypeCheck=1",
+ "mDNSResponderVersion=${MVERS}",
+ _LEGACY_NAT_TRAVERSAL_,
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ MVERS = "\"(Engineering Build)\"";
+ PREBINDING = NO;
+ WARNING_CFLAGS = (
+ "-W",
+ "-Wall",
+ "-Wmissing-prototypes",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ );
+ YACC_GENERATED_FILE_STEM = Standard;
+ };
+ name = Development;
+ };
+ D284BE6E0ADD80740027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ HEADER_SEARCH_PATHS = (
+ ../mDNSShared,
+ "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+ "${CONFIGURATION_TEMP_DIR}",
+ );
+ INSTALL_PATH = /usr/sbin;
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.4;
+ OTHER_CFLAGS = (
+ "$(inherited)",
+ "-no-cpp-precomp",
+ );
+ OTHER_LDFLAGS = "-ldnsinfo";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = mDNSResponder;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = (
+ "-sectorder",
+ __TEXT,
+ __text,
+ mDNSResponder.order,
+ );
+ STRIPFLAGS = "-S";
+ };
+ name = Development;
+ };
+ D284BE930ADD80800027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "MDNS_DEBUGMSGS=1",
+ );
+ HEADER_SEARCH_PATHS = (
+ ../mDNSShared,
+ "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+ "${CONFIGURATION_TEMP_DIR}",
+ );
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.4;
+ OTHER_CFLAGS = (
+ "$(inherited)",
+ "-no-cpp-precomp",
+ );
+ OTHER_LDFLAGS = "-ldnsinfo";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = mDNSResponder.debug;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = (
+ "-sectorder",
+ __TEXT,
+ __text,
+ mDNSResponder.order,
+ );
+ STRIPFLAGS = "-S";
+ };
+ name = Development;
+ };
+ D284BEA10ADD808B0027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ INSTALL_PATH = /usr/bin;
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "-no-cpp-precomp";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = mDNS;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ };
+ name = Development;
+ };
+ D284BEAE0ADD80920027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ HEADER_SEARCH_PATHS = ../mDNSShared;
+ INSTALL_PATH = /usr/bin;
+ MACOSX_DEPLOYMENT_TARGET = 10.3;
+ OTHER_CFLAGS = "-no-cpp-precomp";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "dns-sd";
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ };
+ name = Development;
+ };
+ D284BEBC0ADD809A0027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ EXECUTABLE_EXTENSION = jnilib;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ HEADER_SEARCH_PATHS = (
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers",
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers",
+ "${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build",
+ );
+ INSTALL_PATH = /usr/lib/java;
+ LIBRARY_STYLE = DYNAMIC;
+ MACH_O_TYPE = mh_dylib;
+ OTHER_CFLAGS = "";
+ OTHER_LIBTOOL_FLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = libjdns_sd;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ };
+ name = Development;
+ };
+ D284BED70ADD80A20027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ HEADER_SEARCH_PATHS = (
+ "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+ "${CONFIGURATION_TEMP_DIR}",
+ );
+ INSTALL_PATH = /usr/sbin;
+ LEX = /usr/bin/flex;
+ LEXFLAGS = "";
+ LEX_CASE_INSENSITIVE_SCANNER = YES;
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.4;
+ OTHER_CFLAGS = (
+ "-no-cpp-precomp",
+ "-UAPPLE_OSX_mDNSResponder",
+ );
+ OTHER_LDFLAGS = "-ldnsinfo";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = dnsextd;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ YACC = "/usr/bin/bison -y";
+ };
+ name = Development;
+ };
+ D284BEE60ADD80A70027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ INSTALL_PATH = "/Library/Application Support/Bonjour";
+ MACOSX_DEPLOYMENT_TARGET = 10.3;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = ddnswriteconfig;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ };
+ name = Development;
+ };
+ D284BF090ADD80B00027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ EXPORTED_SYMBOLS_FILE = "";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
+ INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
+ MACOSX_DEPLOYMENT_TARGET = 10.3;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "-twolevel_namespace";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = Bonjour;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ WRAPPER_EXTENSION = prefPane;
+ };
+ name = Development;
+ };
+ FFA572380AF18F1C0055A0F1 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ INSTALL_PATH = /usr/local/lib/system;
+ PRODUCT_NAME = dns_sd_debug;
+ };
+ name = Development;
+ };
+ FFA572440AF18F450055A0F1 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ GENERATE_PROFILING_CODE = YES;
+ INSTALL_PATH = /usr/local/lib/system;
+ PRODUCT_NAME = dns_sd_profile;
+ };
+ name = Development;
+ };
+ FFA5726F0AF191200055A0F1 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ PRODUCT_NAME = SystemLibraries;
+ };
+ name = Development;
+ };
+ FFB7657F0AEED99D00583A2C /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ PRODUCT_NAME = "Build All";
+ };
+ name = Development;
+ };
+ FFB7658A0AEED9FB00583A2C /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ INSTALL_PATH = /usr/local/lib/system;
+ PRODUCT_NAME = dns_sd;
+ };
+ name = Development;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 03067D740C83A3CB0022BE1F /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2E0405F20C31955500F13B59 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE1C0ADD78180027CCDF /* Build configuration list for PBXLibraryTarget "dns_sd.jar" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE1D0ADD78180027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE290ADD78180027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE2C0ADD78180027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE6E0ADD80740027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE930ADD80800027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BEA00ADD808B0027CCDF /* Build configuration list for PBXNativeTarget "mDNS tool" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BEA10ADD808B0027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BEAE0ADD80920027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BEBC0ADD809A0027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BED70ADD80A20027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BEE60ADD80A70027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BF090ADD80B00027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFA572380AF18F1C0055A0F1 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd profile" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFA572440AF18F450055A0F1 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibraries" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFA5726F0AF191200055A0F1 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFB7657F0AEED99D00583A2C /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFB7658A0AEED9FB00583A2C /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
--- /dev/null
+.\" -*- tab-width: 4 -*-
+.\"
+.\" Copyright (c) 2007 Apple Computer, Inc. All Rights Reserved.
+.\"
+.\" Licensed under the Apache License, Version 2.0 (the "License");
+.\" you may not use this file except in compliance with the License.
+.\" You may obtain a copy of the License at
+.\"
+.\" http://www.apache.org/licenses/LICENSE-2.0
+.\"
+.\" Unless required by applicable law or agreed to in writing, software
+.\" distributed under the License is distributed on an "AS IS" BASIS,
+.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+.\" See the License for the specific language governing permissions and
+.\" limitations under the License.
+.\"
+.\" $Log: mDNSResponderHelper.8,v $
+.\" Revision 1.1 2007/08/08 22:34:59 mcguire
+.\" <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+.\"
+.\"
+.\"
+.Dd August 2007 \" Date
+.Dt mDNSResponderHelper 8 \" Document Title
+.Os Darwin \" Operating System
+.\"
+.Sh NAME
+.Nm mDNSResponderHelper
+.Nd mDNS privilege separation helper \" Name Description for whatis database
+.\"
+.Sh SYNOPSIS
+.Nm
+.\"
+.Sh DESCRIPTION
+.Nm
+is an executable invoked by
+.Nm launchd
+to provide privilege separation
+to the
+.Nm mDNSResponder
+daemon.
+.Pp
+.Nm
+has no user-specifiable command-line arguments, and users should not run
+.Nm
+manually.
+.Sh FILES
+.Pa /usr/sbin/mDNSResponderHelper \" Pathname
+.\"
+.Sh SEE ALSO
+.Xr mDNSResponder 8
+.\"
+.Sh BUGS
+.Nm
+bugs are tracked in Apple Radar component "mDNSResponder".
+.\"
+.Sh HISTORY
+The
+.Nm
+first appeared in Mac OS X 10.5 (Leopard).
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!-- To run mDNSResponderHelper on Tiger, place this file into /etc/mach_init.d -->
+<plist version="1.0">
+<dict>
+ <key>ServiceName</key>
+ <string>com.apple.mDNSResponderHelper</string>
+ <key>Command</key>
+ <string>/usr/sbin/mDNSResponderHelper</string>
+ <key>OnDemand</key>
+ <true/>
+</dict>
+</plist>
--- /dev/null
+/*
+ * Copyright (c) 2003-2007 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* $FreeBSD: src/lib/libipsec/pfkey.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
+/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/pfkeyv2.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+
+#define CALLOC(size, cast) (cast)calloc(1, (size))
+
+static int findsupportedmap __P((int));
+static int setsupportedmap __P((struct sadb_supported *));
+static struct sadb_alg *findsupportedalg __P((u_int, u_int));
+static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,
+ u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,
+ u_int32_t, u_int32_t, u_int32_t));
+static int pfkey_send_x2 __P((int, u_int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t));
+static int pfkey_send_x3 __P((int, u_int, u_int));
+static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+ char *, int, u_int32_t));
+static int pfkey_send_x5 __P((int, u_int, u_int32_t));
+
+static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int,
+ u_int, u_int32_t, pid_t));
+static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,
+ u_int, u_int, u_int32_t));
+static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,
+ struct sockaddr *, u_int, u_int));
+static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));
+static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,
+ u_int32_t, u_int32_t, u_int32_t));
+static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t));
+
+/*
+ * make and search supported algorithm structure.
+ */
+static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, };
+
+static int supported_map[] = {
+ SADB_SATYPE_AH,
+ SADB_SATYPE_ESP,
+ SADB_X_SATYPE_IPCOMP,
+};
+
+static int
+findsupportedmap(satype)
+ int satype;
+{
+ int i;
+
+ for (i = 0; (unsigned int)i < sizeof(supported_map)/sizeof(supported_map[0]); i++)
+ if (supported_map[i] == satype)
+ return i;
+ return -1;
+}
+
+static struct sadb_alg *
+findsupportedalg(satype, alg_id)
+ u_int satype, alg_id;
+{
+ int algno;
+ int tlen;
+ caddr_t p;
+
+ /* validity check */
+ algno = findsupportedmap(satype);
+ if (algno == -1) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return NULL;
+ }
+ if (ipsec_supported[algno] == NULL) {
+ __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
+ return NULL;
+ }
+
+ tlen = ipsec_supported[algno]->sadb_supported_len
+ - sizeof(struct sadb_supported);
+ p = (caddr_t)(ipsec_supported[algno] + 1);
+ while (tlen > 0) {
+ if ((unsigned int)tlen < sizeof(struct sadb_alg)) {
+ /* invalid format */
+ break;
+ }
+ if (((struct sadb_alg *)p)->sadb_alg_id == alg_id)
+ return (struct sadb_alg *)p;
+
+ tlen -= sizeof(struct sadb_alg);
+ p += sizeof(struct sadb_alg);
+ }
+
+ __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return NULL;
+}
+
+static int
+setsupportedmap(sup)
+ struct sadb_supported *sup;
+{
+ struct sadb_supported **ipsup;
+
+ switch (sup->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ if (*ipsup)
+ free(*ipsup);
+
+ *ipsup = malloc(sup->sadb_supported_len);
+ if (!*ipsup) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ memcpy(*ipsup, sup, sup->sadb_supported_len);
+
+ return 0;
+}
+
+/*
+ * check key length against algorithm specified.
+ * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the
+ * augument, and only calls to ipsec_check_keylen2();
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_check_keylen(supported, alg_id, keylen)
+ u_int supported;
+ u_int alg_id;
+ u_int keylen;
+{
+ int satype;
+
+ /* validity check */
+ switch (supported) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ satype = SADB_SATYPE_AH;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ satype = SADB_SATYPE_ESP;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ return ipsec_check_keylen2(satype, alg_id, keylen);
+}
+
+/*
+ * check key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_check_keylen2(satype, alg_id, keylen)
+ u_int satype;
+ u_int alg_id;
+ u_int keylen;
+{
+ struct sadb_alg *alg;
+
+ alg = findsupportedalg(satype, alg_id);
+ if (!alg)
+ return -1;
+
+ if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {
+ __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * get max/min key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_get_keylen(supported, alg_id, alg0)
+ u_int supported, alg_id;
+ struct sadb_alg *alg0;
+{
+ struct sadb_alg *alg;
+ u_int satype;
+
+ /* validity check */
+ if (!alg0) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ switch (supported) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ satype = SADB_SATYPE_AH;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ satype = SADB_SATYPE_ESP;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ alg = findsupportedalg(satype, alg_id);
+ if (!alg)
+ return -1;
+
+ memcpy(alg0, alg, sizeof(*alg0));
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * set the rate for SOFT lifetime against HARD one.
+ * If rate is more than 100 or equal to zero, then set to 100.
+ */
+static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;
+
+u_int
+pfkey_set_softrate(type, rate)
+ u_int type, rate;
+{
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ if (rate > 100 || rate == 0)
+ rate = 100;
+
+ switch (type) {
+ case SADB_X_LIFETIME_ALLOCATIONS:
+ soft_lifetime_allocations_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_BYTES:
+ soft_lifetime_bytes_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_ADDTIME:
+ soft_lifetime_addtime_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_USETIME:
+ soft_lifetime_usetime_rate = rate;
+ return 0;
+ }
+
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return 1;
+}
+
+/*
+ * get current rate for SOFT lifetime against HARD one.
+ * ATTENTION: ~0 is returned if invalid type was passed.
+ */
+u_int
+pfkey_get_softrate(type)
+ u_int type;
+{
+ switch (type) {
+ case SADB_X_LIFETIME_ALLOCATIONS:
+ return soft_lifetime_allocations_rate;
+ case SADB_X_LIFETIME_BYTES:
+ return soft_lifetime_bytes_rate;
+ case SADB_X_LIFETIME_ADDTIME:
+ return soft_lifetime_addtime_rate;
+ case SADB_X_LIFETIME_USETIME:
+ return soft_lifetime_usetime_rate;
+ }
+
+ return ~0;
+}
+
+/*
+ * sending SADB_GETSPI message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t min, max, reqid, seq;
+{
+ struct sadb_msg *newmsg;
+ caddr_t ep;
+ int len;
+ int need_spirange = 0;
+ caddr_t p;
+ int plen;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ if (min > max || (min > 0 && min <= 255)) {
+ __ipsec_errcode = EIPSEC_INVAL_SPI;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to send. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_x_sa2)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if (min > (u_int32_t)255 && max < (u_int32_t)~0) {
+ need_spirange++;
+ len += sizeof(struct sadb_spirange);
+ }
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI,
+ len, satype, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* set sadb_address for source */
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* set sadb_address for destination */
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* proccessing spi range */
+ if (need_spirange) {
+ struct sadb_spirange spirange;
+
+ if (p + sizeof(spirange) > ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ memset(&spirange, 0, sizeof(spirange));
+ spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));
+ spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ spirange.sadb_spirange_min = min;
+ spirange.sadb_spirange_max = max;
+
+ memcpy(p, &spirange, sizeof(spirange));
+
+ p += sizeof(spirange);
+ }
+ if (p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_UPDATE message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int satype, mode, wsize;
+ struct sockaddr *src, *dst;
+ u_int32_t spi, reqid;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc;
+ u_int64_t l_bytes, l_addtime, l_usetime;
+ u_int32_t seq;
+{
+ int len;
+ if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
+ reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_ADD message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int satype, mode, wsize;
+ struct sockaddr *src, *dst;
+ u_int32_t spi, reqid;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc;
+ u_int64_t l_bytes, l_addtime, l_usetime;
+ u_int32_t seq;
+{
+ int len;
+ if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
+ reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_delete(so, satype, mode, src, dst, spi)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ int len;
+ if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DELETE without spi to the kernel. This is
+ * the "delete all" request (an extension also present in
+ * Solaris).
+ *
+ * OUT:
+ * positive: success and return length sent
+ * -1 : error occured, and set errno
+ */
+int
+pfkey_send_delete_all(so, satype, mode, src, dst)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ (void)mode;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0,
+ getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_GET message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_get(so, satype, mode, src, dst, spi)
+ int so;
+ u_int satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ int len;
+ if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_REGISTER message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_register(so, satype)
+ int so;
+ u_int satype;
+{
+ int len, algno;
+
+ if (satype == PF_UNSPEC) {
+ for (algno = 0;
+ (unsigned int)algno < sizeof(supported_map)/sizeof(supported_map[0]);
+ algno++) {
+ if (ipsec_supported[algno]) {
+ free(ipsec_supported[algno]);
+ ipsec_supported[algno] = NULL;
+ }
+ }
+ } else {
+ algno = findsupportedmap(satype);
+ if (algno == -1) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if (ipsec_supported[algno]) {
+ free(ipsec_supported[algno]);
+ ipsec_supported[algno] = NULL;
+ }
+ }
+
+ if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * OUT:
+ * 0: success and return length sent.
+ * -1: error occured, and set errno.
+ */
+int
+pfkey_recv_register(so)
+ int so;
+{
+ pid_t pid = getpid();
+ struct sadb_msg *newmsg;
+ int error = -1;
+
+ /* receive message */
+ do {
+ if ((newmsg = pfkey_recv(so)) == NULL)
+ return -1;
+ } while (newmsg->sadb_msg_type != SADB_REGISTER
+ || (pid_t)newmsg->sadb_msg_pid != pid);
+
+ /* check and fix */
+ newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
+
+ error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len);
+ free(newmsg);
+
+ if (error == 0)
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return error;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * NOTE: sadb_msg_len must be host order.
+ * IN:
+ * tlen: msg length, it's to makeing sure.
+ * OUT:
+ * 0: success and return length sent.
+ * -1: error occured, and set errno.
+ */
+int
+pfkey_set_supported(msg, tlen)
+ struct sadb_msg *msg;
+ int tlen;
+{
+ struct sadb_supported *sup;
+ caddr_t p;
+ caddr_t ep;
+
+ /* validity */
+ if (msg->sadb_msg_len != tlen) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ p = (caddr_t)msg;
+ ep = p + tlen;
+
+ p += sizeof(struct sadb_msg);
+
+ while (p < ep) {
+ sup = (struct sadb_supported *)p;
+ if (ep < p + sizeof(*sup) ||
+ (size_t)PFKEY_EXTLEN(sup) < sizeof(*sup) ||
+ ep < p + sup->sadb_supported_len) {
+ /* invalid format */
+ break;
+ }
+
+ switch (sup->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* fixed length */
+ sup->sadb_supported_len = PFKEY_EXTLEN(sup);
+
+ /* set supported map */
+ if (setsupportedmap(sup) != 0)
+ return -1;
+
+ p += sup->sadb_supported_len;
+ }
+
+ if (p != ep) {
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return 0;
+}
+
+/*
+ * sending SADB_FLUSH message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_flush(so, satype)
+ int so;
+ u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DUMP message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_dump(so, satype)
+ int so;
+ u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_PROMISC message to the kernel.
+ * NOTE that this function handles promisc mode toggle only.
+ * IN:
+ * flag: set promisc off if zero, set promisc on if non-zero.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ * 0 : error occured, and set errno.
+ * others: a pointer to new allocated buffer in which supported
+ * algorithms is.
+ */
+int
+pfkey_send_promisc_toggle(so, flag)
+ int so;
+ int flag;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+ policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ u_int64_t ltime, vtime;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+ src, prefs, dst, prefd, proto,
+ ltime, vtime,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+ policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ u_int64_t ltime, vtime;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+ src, prefs, dst, prefd, proto,
+ ltime, vtime,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if (policylen != sizeof(struct sadb_x_policy)) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete2(so, spid)
+ int so;
+ u_int32_t spid;
+{
+ int len;
+
+ if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDGET message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdget(so, spid)
+ int so;
+ u_int32_t spid;
+{
+ int len;
+
+ if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDSETIDX message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int prefs, prefd, proto;
+ caddr_t policy;
+ int policylen;
+ u_int32_t seq;
+{
+ int len;
+
+ if (policylen != sizeof(struct sadb_x_policy)) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_SPDFLUSH message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdflush(so)
+ int so;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_SPDDUMP message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddump(so)
+ int so;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
+ return -1;
+
+ return len;
+}
+
+/* sending SADB_ADD or SADB_UPDATE message to the kernel */
+static int
+pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+ int so;
+ u_int type, satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi, reqid;
+ u_int wsize;
+ caddr_t keymat;
+ u_int e_type, e_keylen, a_type, a_keylen, flags;
+ u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ switch (satype) {
+ case SADB_SATYPE_ESP:
+ if (e_type == SADB_EALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_AH:
+ if (e_type != SADB_EALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type == SADB_AALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_X_SATYPE_IPCOMP:
+ if (e_type == SADB_X_CALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type != SADB_AALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_sa)
+ + sizeof(struct sadb_x_sa2)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len)
+ + sizeof(struct sadb_lifetime)
+ + sizeof(struct sadb_lifetime);
+
+ if (e_type != SADB_EALG_NONE)
+ len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
+ if (a_type != SADB_AALG_NONE)
+ len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ satype, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ if (e_type != SADB_EALG_NONE) {
+ p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
+ keymat, e_keylen);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ }
+ if (a_type != SADB_AALG_NONE) {
+ p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
+ keymat + e_keylen, a_keylen);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ }
+
+ /* set sadb_lifetime for destination */
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+ l_alloc, l_bytes, l_addtime, l_usetime);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
+ l_alloc, l_bytes, l_addtime, l_usetime);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_DELETE or SADB_GET message to the kernel */
+static int
+pfkey_send_x2(so, type, satype, mode, src, dst, spi)
+ int so;
+ u_int type, satype, mode;
+ struct sockaddr *src, *dst;
+ u_int32_t spi;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ (void)mode;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_sa)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+ getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
+ * to the kernel
+ */
+static int
+pfkey_send_x3(so, type, satype)
+ int so;
+ u_int type, satype;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ caddr_t ep;
+
+ /* validity check */
+ switch (type) {
+ case SADB_X_PROMISC:
+ if (satype != 0 && satype != 1) {
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ default:
+ switch (satype) {
+ case SADB_SATYPE_UNSPEC:
+ case SADB_SATYPE_AH:
+ case SADB_SATYPE_ESP:
+ case SADB_X_SATYPE_IPCOMP:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ }
+
+ /* create new sadb_msg to send. */
+ len = sizeof(struct sadb_msg);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+ getpid());
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_X_SPDADD message to the kernel */
+static int
+pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
+ ltime, vtime, policy, policylen, seq)
+ int so;
+ struct sockaddr *src, *dst;
+ u_int type, prefs, prefd, proto;
+ u_int64_t ltime, vtime;
+ char *policy;
+ int policylen;
+ u_int32_t seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+ if (prefs > (u_int)plen || prefd > (u_int)plen) {
+ __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_lifetime)
+ + policylen;
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ SADB_SATYPE_UNSPEC, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+ 0, 0, ltime, vtime);
+ if (!p || p + policylen != ep) {
+ free(newmsg);
+ return -1;
+ }
+ memcpy(p, policy, policylen);
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
+static int
+pfkey_send_x5(so, type, spid)
+ int so;
+ u_int type;
+ u_int32_t spid;
+{
+ struct sadb_msg *newmsg;
+ struct sadb_x_policy xpl;
+ int len;
+ caddr_t p;
+ caddr_t ep;
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(xpl);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ SADB_SATYPE_UNSPEC, 0, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ if (p + sizeof(xpl) != ep) {
+ free(newmsg);
+ return -1;
+ }
+ memset(&xpl, 0, sizeof(xpl));
+ xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl));
+ xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ xpl.sadb_x_policy_id = spid;
+ memcpy(p, &xpl, sizeof(xpl));
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * open a socket.
+ * OUT:
+ * -1: fail.
+ * others : success and return value of socket.
+ */
+int
+pfkey_open()
+{
+ int so;
+ const int bufsiz = 128 * 1024; /*is 128K enough?*/
+
+ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ /*
+ * This is a temporary workaround for KAME PR 154.
+ * Don't really care even if it fails.
+ */
+ (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz));
+ (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz));
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return so;
+}
+
+/*
+ * close a socket.
+ * OUT:
+ * 0: success.
+ * -1: fail.
+ */
+void
+pfkey_close(so)
+ int so;
+{
+ (void)close(so);
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return;
+}
+
+/*
+ * receive sadb_msg data, and return pointer to new buffer allocated.
+ * Must free this buffer later.
+ * OUT:
+ * NULL : error occured.
+ * others : a pointer to sadb_msg structure.
+ *
+ * XXX should be rewritten to pass length explicitly
+ */
+struct sadb_msg *
+pfkey_recv(so)
+ int so;
+{
+ struct sadb_msg buf, *newmsg;
+ int len, reallen;
+
+ while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) {
+ if (errno == EINTR)
+ continue;
+ __ipsec_set_strerror(strerror(errno));
+ return NULL;
+ }
+
+ if ((size_t)len < sizeof(buf)) {
+ recv(so, (caddr_t)&buf, sizeof(buf), 0);
+ __ipsec_errcode = EIPSEC_MAX;
+ return NULL;
+ }
+
+ /* read real message */
+ reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
+ if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return NULL;
+ }
+
+ while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) {
+ if (errno == EINTR)
+ continue;
+ __ipsec_set_strerror(strerror(errno));
+ free(newmsg);
+ return NULL;
+ }
+
+ if (len != reallen) {
+ __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ free(newmsg);
+ return NULL;
+ }
+
+ /* don't trust what the kernel says, validate! */
+ if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) {
+ __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ free(newmsg);
+ return NULL;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return newmsg;
+}
+
+/*
+ * send message to a socket.
+ * OUT:
+ * others: success and return length sent.
+ * -1 : fail.
+ */
+int
+pfkey_send(so, msg, len)
+ int so;
+ struct sadb_msg *msg;
+ int len;
+{
+ if ((len = send(so, (caddr_t)msg, len, 0)) < 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * %%% Utilities
+ * NOTE: These functions are derived from netkey/key.c in KAME.
+ */
+/*
+ * set the pointer to each header in this message buffer.
+ * IN: msg: pointer to message buffer.
+ * mhp: pointer to the buffer initialized like below:
+ * caddr_t mhp[SADB_EXT_MAX + 1];
+ * OUT: -1: invalid.
+ * 0: valid.
+ *
+ * XXX should be rewritten to obtain length explicitly
+ */
+int
+pfkey_align(msg, mhp)
+ struct sadb_msg *msg;
+ caddr_t *mhp;
+{
+ struct sadb_ext *ext;
+ int i;
+ caddr_t p;
+ caddr_t ep; /* XXX should be passed from upper layer */
+
+ /* validity check */
+ if (msg == NULL || mhp == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ /* initialize */
+ for (i = 0; i < SADB_EXT_MAX + 1; i++)
+ mhp[i] = NULL;
+
+ mhp[0] = (caddr_t)msg;
+
+ /* initialize */
+ p = (caddr_t) msg;
+ ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len);
+
+ /* skip base header */
+ p += sizeof(struct sadb_msg);
+
+ while (p < ep) {
+ ext = (struct sadb_ext *)p;
+ if (ep < p + sizeof(*ext) || (size_t)PFKEY_EXTLEN(ext) < sizeof(*ext) ||
+ ep < p + PFKEY_EXTLEN(ext)) {
+ /* invalid format */
+ break;
+ }
+
+ /* duplicate check */
+ /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
+ if (mhp[ext->sadb_ext_type] != NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return -1;
+ }
+
+ /* set pointer */
+ switch (ext->sadb_ext_type) {
+ case SADB_EXT_SA:
+ case SADB_EXT_LIFETIME_CURRENT:
+ case SADB_EXT_LIFETIME_HARD:
+ case SADB_EXT_LIFETIME_SOFT:
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_EXT_KEY_AUTH:
+ /* XXX should to be check weak keys. */
+ case SADB_EXT_KEY_ENCRYPT:
+ /* XXX should to be check weak keys. */
+ case SADB_EXT_IDENTITY_SRC:
+ case SADB_EXT_IDENTITY_DST:
+ case SADB_EXT_SENSITIVITY:
+ case SADB_EXT_PROPOSAL:
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ case SADB_EXT_SPIRANGE:
+ case SADB_X_EXT_POLICY:
+ case SADB_X_EXT_SA2:
+ mhp[ext->sadb_ext_type] = (caddr_t)ext;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return -1;
+ }
+
+ p += PFKEY_EXTLEN(ext);
+ }
+
+ if (p != ep) {
+ __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * check basic usage for sadb_msg,
+ * NOTE: This routine is derived from netkey/key.c in KAME.
+ * IN: msg: pointer to message buffer.
+ * mhp: pointer to the buffer initialized like below:
+ *
+ * caddr_t mhp[SADB_EXT_MAX + 1];
+ *
+ * OUT: -1: invalid.
+ * 0: valid.
+ */
+int
+pfkey_check(mhp)
+ caddr_t *mhp;
+{
+ struct sadb_msg *msg;
+
+ /* validity check */
+ if (mhp == NULL || mhp[0] == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ msg = (struct sadb_msg *)mhp[0];
+
+ /* check version */
+ if (msg->sadb_msg_version != PF_KEY_V2) {
+ __ipsec_errcode = EIPSEC_INVAL_VERSION;
+ return -1;
+ }
+
+ /* check type */
+ if (msg->sadb_msg_type > SADB_MAX) {
+ __ipsec_errcode = EIPSEC_INVAL_MSGTYPE;
+ return -1;
+ }
+
+ /* check SA type */
+ switch (msg->sadb_msg_satype) {
+ case SADB_SATYPE_UNSPEC:
+ switch (msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_ACQUIRE:
+ case SADB_EXPIRE:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_ESP:
+ case SADB_SATYPE_AH:
+ case SADB_X_SATYPE_IPCOMP:
+ switch (msg->sadb_msg_type) {
+ case SADB_X_SPDADD:
+ case SADB_X_SPDDELETE:
+ case SADB_X_SPDGET:
+ case SADB_X_SPDDUMP:
+ case SADB_X_SPDFLUSH:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_RSVP:
+ case SADB_SATYPE_OSPFV2:
+ case SADB_SATYPE_RIPV2:
+ case SADB_SATYPE_MIP:
+ __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return -1;
+ case 1: /* XXX: What does it do ? */
+ if (msg->sadb_msg_type == SADB_X_PROMISC)
+ break;
+ /*FALLTHROUGH*/
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* check field of upper layer protocol and address family */
+ if (mhp[SADB_EXT_ADDRESS_SRC] != NULL
+ && mhp[SADB_EXT_ADDRESS_DST] != NULL) {
+ struct sadb_address *src0, *dst0;
+
+ src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
+ dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+
+ if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+ __ipsec_errcode = EIPSEC_PROTO_MISMATCH;
+ return -1;
+ }
+
+ if (PFKEY_ADDR_SADDR(src0)->sa_family
+ != PFKEY_ADDR_SADDR(dst0)->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /*
+ * prefixlen == 0 is valid because there must be the case
+ * all addresses are matched.
+ */
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * set data into sadb_msg.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid)
+ caddr_t buf;
+ caddr_t lim;
+ u_int type, satype;
+ u_int tlen;
+ u_int32_t seq;
+ pid_t pid;
+{
+ struct sadb_msg *p;
+ u_int len;
+
+ p = (struct sadb_msg *)buf;
+ len = sizeof(struct sadb_msg);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_msg_version = PF_KEY_V2;
+ p->sadb_msg_type = type;
+ p->sadb_msg_errno = 0;
+ p->sadb_msg_satype = satype;
+ p->sadb_msg_len = PFKEY_UNIT64(tlen);
+ p->sadb_msg_reserved = 0;
+ p->sadb_msg_seq = seq;
+ p->sadb_msg_pid = (u_int32_t)pid;
+
+ return(buf + len);
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags)
+ caddr_t buf;
+ caddr_t lim;
+ u_int32_t spi, flags;
+ u_int wsize, auth, enc;
+{
+ struct sadb_sa *p;
+ u_int len;
+
+ p = (struct sadb_sa *)buf;
+ len = sizeof(struct sadb_sa);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_sa_len = PFKEY_UNIT64(len);
+ p->sadb_sa_exttype = SADB_EXT_SA;
+ p->sadb_sa_spi = spi;
+ p->sadb_sa_replay = wsize;
+ p->sadb_sa_state = SADB_SASTATE_LARVAL;
+ p->sadb_sa_auth = auth;
+ p->sadb_sa_encrypt = enc;
+ p->sadb_sa_flags = flags;
+
+ return(buf + len);
+}
+
+/*
+ * set data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ * prefixlen is in bits.
+ */
+static caddr_t
+pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto)
+ caddr_t buf;
+ caddr_t lim;
+ u_int exttype;
+ struct sockaddr *saddr;
+ u_int prefixlen;
+ u_int ul_proto;
+{
+ struct sadb_address *p;
+ u_int len;
+
+ p = (struct sadb_address *)buf;
+ len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_address_len = PFKEY_UNIT64(len);
+ p->sadb_address_exttype = exttype & 0xffff;
+ p->sadb_address_proto = ul_proto & 0xff;
+ p->sadb_address_prefixlen = prefixlen;
+ p->sadb_address_reserved = 0;
+
+ memcpy(p + 1, saddr, saddr->sa_len);
+
+ return(buf + len);
+}
+
+/*
+ * set sadb_key structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadbkey(buf, lim, type, key, keylen)
+ caddr_t buf;
+ caddr_t lim;
+ caddr_t key;
+ u_int type, keylen;
+{
+ struct sadb_key *p;
+ u_int len;
+
+ p = (struct sadb_key *)buf;
+ len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_key_len = PFKEY_UNIT64(len);
+ p->sadb_key_exttype = type;
+ p->sadb_key_bits = keylen << 3;
+ p->sadb_key_reserved = 0;
+
+ memcpy(p + 1, key, keylen);
+
+ return buf + len;
+}
+
+/*
+ * set sadb_lifetime structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime)
+ caddr_t buf;
+ caddr_t lim;
+ u_int type;
+ u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
+{
+ struct sadb_lifetime *p;
+ u_int len;
+
+ p = (struct sadb_lifetime *)buf;
+ len = sizeof(struct sadb_lifetime);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_lifetime_len = PFKEY_UNIT64(len);
+ p->sadb_lifetime_exttype = type;
+
+ switch (type) {
+ case SADB_EXT_LIFETIME_SOFT:
+ p->sadb_lifetime_allocations
+ = (l_alloc * soft_lifetime_allocations_rate) /100;
+ p->sadb_lifetime_bytes
+ = (l_bytes * soft_lifetime_bytes_rate) /100;
+ p->sadb_lifetime_addtime
+ = (l_addtime * soft_lifetime_addtime_rate) /100;
+ p->sadb_lifetime_usetime
+ = (l_usetime * soft_lifetime_usetime_rate) /100;
+ break;
+ case SADB_EXT_LIFETIME_HARD:
+ p->sadb_lifetime_allocations = l_alloc;
+ p->sadb_lifetime_bytes = l_bytes;
+ p->sadb_lifetime_addtime = l_addtime;
+ p->sadb_lifetime_usetime = l_usetime;
+ break;
+ }
+
+ return buf + len;
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbxsa2(buf, lim, mode0, reqid)
+ caddr_t buf;
+ caddr_t lim;
+ u_int32_t mode0;
+ u_int32_t reqid;
+{
+ struct sadb_x_sa2 *p;
+ u_int8_t mode = mode0 & 0xff;
+ u_int len;
+
+ p = (struct sadb_x_sa2 *)buf;
+ len = sizeof(struct sadb_x_sa2);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_x_sa2_len = PFKEY_UNIT64(len);
+ p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ p->sadb_x_sa2_mode = mode;
+ p->sadb_x_sa2_reqid = reqid;
+
+ return(buf + len);
+}
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Client.c,v $
+Revision 1.20 2007/07/27 19:30:41 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
+
+Revision 1.19 2007/04/16 20:49:39 cheshire
+Fix compile errors for mDNSPosix build
+
+Revision 1.18 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.17 2006/06/12 18:22:42 cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
+
Revision 1.16 2005/02/04 01:00:53 cheshire
Add '-d' command-line option to specify domain to browse
#define RR_CACHE_SIZE 500
static CacheEntity gRRCache[RR_CACHE_SIZE];
-static const char *gProgramName = "mDNSResponderPosix";
+mDNSexport const char ProgramName[] = "mDNSClientPosix";
+
+static const char *gProgramName = ProgramName;
-static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
// A callback from the core mDNS code that indicates that we've received a
// response to our query. Note that this code runs on the main thread
// (in fact, there is only one thread!), so we can safely printf the results.
result = 2;
}
if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
- fprintf(stderr, "%s: Finished with status %ld, result %d\n", gProgramName, status, result);
+ fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result);
}
return 0;
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ExampleClientApp.c,v $
+Revision 1.14 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.13 2006/02/23 23:38:43 cheshire
+<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
+
Revision 1.12 2004/11/30 22:37:00 cheshire
Update copyright dates and add "Mode: C; tab-width: 4" headers
#include <string.h> // For strlen() etc.
#include <unistd.h> // For select()
#include <errno.h> // For errno, EINTR
-#include <arpa/inet.h> // For inet_addr()
#include <netinet/in.h> // For INADDR_NONE
+#include <arpa/inet.h> // For inet_addr()
#include <netdb.h> // For gethostbyname()
#include <signal.h> // For SIGINT, etc.
*
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ExampleClientApp.h,v $
+Revision 1.7 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.6 2004/11/30 22:37:00 cheshire
Update copyright dates and add "Mode: C; tab-width: 4" headers
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*
* Formatting notes:
* This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
Change History (most recent first):
$Log: Identify.c,v $
-Revision 1.34 2004/12/16 20:17:11 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.33 2004/11/30 22:37:00 cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.32 2004/10/19 21:33:21 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.31 2004/10/16 00:17:00 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.30 2004/09/21 23:29:51 cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
-
-Revision 1.29 2004/09/17 01:08:53 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.28 2004/09/17 00:31:52 cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.27 2004/09/16 01:58:22 cheshire
-Fix compiler warnings
-
-Revision 1.26 2004/08/24 21:55:07 cheshire
-Don't try to build IPv6 code on systems that don't have IPv6
-
-Revision 1.25 2004/07/20 23:42:37 cheshire
-Update to use only "_services._dns-sd._udp.local." meta-query for service enumeration
-
-Revision 1.24 2004/06/15 02:39:47 cheshire
-When displaying error message, only show command name, not entire path
-
-Revision 1.23 2004/05/18 23:51:26 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.22 2004/04/20 22:43:28 cheshire
-Use _services._dns-sd._udp query, as documented in
-<http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd-02.txt>
-
-Revision 1.21 2004/01/28 21:38:57 cheshire
-Also ask target host for _services._mdns._udp.local. list
-
-Revision 1.20 2004/01/28 19:04:38 cheshire
-Fix Ctrl-C handling when multiple targets are specified
-
-Revision 1.19 2004/01/28 03:49:30 cheshire
-Enhanced mDNSIdentify to make use of new targeted-query capability
-
-Revision 1.18 2004/01/27 19:06:51 cheshire
-Remove workaround for WWDC 2003 bug; no one has run that buggy build for a long time
-
-Revision 1.17 2004/01/22 03:57:00 cheshire
-Use the new meta-interface mDNSInterface_ForceMCast. This restores mDNSIdentify's
-ability to use multicast queries with non-link-local target addresses, like 17.x.x.x.
-
-Revision 1.16 2004/01/22 00:03:32 cheshire
-Add while() loop so that a list of targets may be specified on the command line
-
-Revision 1.15 2004/01/21 21:55:06 cheshire
-Don't need to wait for timeout once we've got the information we wanted
-
-Revision 1.14 2003/12/17 00:51:22 cheshire
-Changed mDNSNetMonitor and mDNSIdentify to link the object files
-instead of #including the "DNSCommon.c" "uDNS.c" and source files
-
-Revision 1.13 2003/12/13 03:05:28 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
-
-Revision 1.12 2003/11/14 21:27:09 cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
-
-Revision 1.11 2003/10/30 19:26:38 cheshire
-Fix warnings on certain compilers
-
-Revision 1.10 2003/09/02 20:38:57 cheshire
-#include <signal.h> for Linux
-
-Revision 1.9 2003/08/14 23:57:46 cheshire
-Report if there is no answer at all from the target host
-
-Revision 1.8 2003/08/14 02:19:55 cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+Revision 1.42 2007/07/27 19:30:41 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
-Revision 1.7 2003/08/12 19:56:26 cheshire
-Update to APSL 2.0
+Revision 1.41 2007/04/16 20:49:39 cheshire
+Fix compile errors for mDNSPosix build
-Revision 1.6 2003/08/06 01:46:18 cheshire
-Distinguish no answer from partial answer
+Revision 1.40 2007/02/28 01:51:22 cheshire
+Added comment about reverse-order IP address
-Revision 1.5 2003/08/05 23:56:26 cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-(Right now mDNSPosix.c just reports 255 -- we should fix this)
+Revision 1.39 2007/01/05 08:30:51 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.4 2003/08/04 17:24:48 cheshire
-Combine the three separate A/AAAA/HINFO queries into a single qtype "ANY" query
+Revision 1.38 2007/01/04 20:57:48 cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-Revision 1.3 2003/08/04 17:14:08 cheshire
-Do both AAAA queries in parallel
+Revision 1.37 2006/10/27 01:32:08 cheshire
+Set ReturnIntermed to mDNStrue
-Revision 1.2 2003/08/02 02:25:13 cheshire
-Multiple improvements: Now displays host's name, and all v4 and v6 addresses, as well as HINFO record
+Revision 1.36 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.1 2003/08/01 02:20:02 cheshire
-Add mDNSIdentify tool, used to discover what version of mDNSResponder a particular host is running
+Revision 1.35 2006/06/12 18:22:42 cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
- */
+*/
//*************************************************************************************************************
// Incorporate mDNS.c functionality
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
#define RR_CACHE_SIZE 500
static CacheEntity gRRCache[RR_CACHE_SIZE];
+mDNSexport const char ProgramName[] = "mDNSIdentify";
static volatile int StopNow; // 0 means running, 1 means stop because we got an answer, 2 means stop because of Ctrl-C
static volatile int NumAnswers, NumAddr, NumAAAA, NumHINFO;
__MDNS__mDNSCoreReceive(m, msg, end, srcaddr, srcport, &AllDNSLinkGroup_v4, dstport, InterfaceID);
}
-static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
(void)m; // Unused
(void)question; // Unused
}
}
-static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
(void)m; // Unused
(void)question; // Unused
if (NumHINFO && (NumAddr || NumAAAA)) StopNow = 1;
}
-static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
(void)m; // Unused
(void)question; // Unused
q->LongLived = mDNSfalse;
q->ExpectUnique = mDNStrue;
q->ForceMCast = mDNStrue; // Query via multicast, even for apparently uDNS names like 1.1.1.17.in-addr.arpa.
+ q->ReturnIntermed = mDNStrue;
q->QuestionCallback = callback;
q->QuestionContext = NULL;
gRRCache, RR_CACHE_SIZE,
mDNS_Init_DontAdvertiseLocalAddresses,
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
- if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); }
+ if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); }
signal(SIGINT, HandleSIG); // SIGINT is what you get for a Ctrl-C
signal(SIGTERM, HandleSIG);
if (inet_pton(AF_INET, arg, &s4) == 1)
{
mDNSu8 *p = (mDNSu8 *)&s4;
+ // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]);
printf("%s\n", buffer);
target.type = mDNSAddrType_IPv4;
+# -*- tab-width: 4 -*-
+#
# Copyright (c) 2002-2004, Apple Computer, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
+# IMPORTANT NOTE: This is a Makefile for *GNU make*
+# On some systems, a different program may be the default "make" command.
+# If "make os=xxx" gives lots of errors like "Missing dependency operator",
+# then try typing "gmake os=xxx" instead.
+#
# $Log: Makefile,v $
+# Revision 1.76 2007/07/31 23:39:02 mcguire
+# Don't bail on errors in flex-generated .c files
+#
+# Revision 1.75 2006/08/24 22:41:23 herscher
+# <rdar://problem/4580067> POSIX: dnsextd_parser doesn't compile on Linux
+#
+# Revision 1.74 2006/08/14 23:07:11 cheshire
+# Added "tab-width" emacs header line
+#
+# Revision 1.73 2006/07/07 00:54:08 cheshire
+# <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+# Put intermediate files into "objects" folder instead of mDNSShared source code folder
+#
+# Revision 1.72 2006/07/05 23:53:58 cheshire
+# <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+#
+# Revision 1.71 2006/06/20 23:07:04 rpantos
+# <rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+#
+# Revision 1.70 2006/05/03 23:35:10 cheshire
+# Add missing dependency: NetMonitor.c textually imports mDNS.c
+#
+# Revision 1.69 2006/02/26 23:18:50 cheshire
+# <rdar://problem/4427969> FreeBSD 4 requires "-pthread" option to compile threaded code
+#
+# Revision 1.68 2006/02/26 01:36:54 cheshire
+# Rename the poorly named "LIBFLAGS" as "LINKOPTS"
+#
+# Revision 1.67 2006/02/25 23:14:29 cheshire
+# Add comment suggesting using "gmake" command
+#
+# Revision 1.66 2006/01/06 01:06:17 cheshire
+# <rdar://problem/3978979> Compile library and client programs in one pass
+#
+# Revision 1.65 2005/12/21 21:15:57 cheshire
+# Add missing dependency: Identify.c textually imports mDNS.c
+#
# Revision 1.64 2005/10/25 23:55:47 cheshire
# Add tiger to list of target platforms
#
# Notes:
# $@ means "The file name of the target of the rule"
# $< means "The name of the first prerequisite"
+# $* means "The stem with which an implicit rule matches"
# $+ means "The names of all the prerequisites, with spaces between them, exactly as given"
# For more magic automatic variables, see
-# <http://www.gnu.org/software/make/manual/html_chapter/make_10.html#SEC111>
+# <http://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html>
#############################################################################
JDK = /usr/jdk
CC = @cc
+BISON = @bison
+FLEX = @flex
LD = ld -shared
CP = cp
RM = rm
LN = ln -s -f
-CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
-LIBFLAGS =
+CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
+CFLAGS_PTHREAD =
+LINKOPTS =
+LINKOPTS_PTHREAD = -lpthread
LDSUFFIX = so
JAVACFLAGS_OS = -fPIC -shared -ldns_sd
-DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME
CC = gcc
LD = gcc -shared
-LIBFLAGS = -lsocket -lnsl -lresolv
+LINKOPTS = -lsocket -lnsl -lresolv
JAVACFLAGS_OS += -I$(JDK)/include/solaris
ifneq ($(DEBUG),1)
STRIP = strip
else
ifeq ($(os),linux)
-CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX
+CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX
+FLEXFLAGS_OS = -l
JAVACFLAGS_OS += -I$(JDK)/include/linux
OPTIONALTARG = nss_mdns
OPTINSTALL = InstalledNSS
INSTBASE=$(LOCALBASE)
STARTUPSCRIPTNAME=mdns.sh
CFLAGS_OS =
+# FreeBSD 4 requires threaded code to be compiled and linked using the "-pthread" option,
+# and requires that the "-lpthread" link option NOT be used
+# This appies only to FreeBSD -- "man cc" on FreeBSD says:
+# FreeBSD SPECIFIC OPTIONS
+# -pthread
+# Link a user-threaded process against libc_r instead of libc.
+CFLAGS_PTHREAD = -pthread -D_THREAD_SAFE
+LINKOPTS_PTHREAD = -pthread
JAVACFLAGS_OS += -I$(JDK)/include/freebsd
LDCONFIG = ldconfig
else
ifeq ($(os),jaguar)
CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -DNOT_HAVE_SOCKLEN_T
LD = libtool -dynamic
-LIBFLAGS = -lSystem
+LINKOPTS = -lSystem
LDSUFFIX = dylib
JDK = /System/Library/Frameworks/JavaVM.framework/Home
JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM
ifeq ($(os),panther)
CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror
LD = libtool -dynamic
-LIBFLAGS = -lSystem
+LINKOPTS = -lSystem
LDSUFFIX = dylib
JDK = /System/Library/Frameworks/JavaVM.framework/Home
JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM
CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement #-Wunreachable-code
CC = @gcc-4.0
LD = $(CC) -dynamiclib
-LIBFLAGS = -lSystem
+LINKOPTS = -lSystem
LDSUFFIX = dylib
JDK = /System/Library/Frameworks/JavaVM.framework/Home
JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM
#############################################################################
-all: setup Daemon libdns_sd Client Responder ProxyResponder Identify NetMonitor dnsextd $(OPTIONALTARG)
+all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder Identify NetMonitor dnsextd $(OPTIONALTARG)
-install: setup InstalledDaemon InstalledLib InstalledStartup InstalledManPages $(OPTINSTALL)
+install: setup InstalledDaemon InstalledStartup InstalledLib InstalledManPages InstalledClients $(OPTINSTALL)
# 'setup' sets up the build directory structure the way we want
setup:
# clean removes targets and objects
clean:
- if test -d $(OBJDIR) ; then rm -r $(OBJDIR) ; fi
- if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi
+ @if test -d $(OBJDIR) ; then rm -r $(OBJDIR) ; fi
+ @if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi
+ @$(MAKE) -C ../Clients clean
#############################################################################
$(OBJDIR)/DNSDigest.c.o $(OBJDIR)/uDNS.c.o $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/uds_daemon.c.o \
$(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/dnssd_ipc.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/PlatformCommon.c.o
+# dnsextd target build dnsextd
+DNSEXTDOBJ = $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/DNSDigest.c.o \
+ $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/PlatformCommon.c.o $(OBJDIR)/dnsextd_parser.y.o $(OBJDIR)/dnsextd_lexer.l.o
+
Daemon: setup $(BUILDDIR)/mdnsd
@echo "Responder daemon done"
$(BUILDDIR)/mdnsd: $(DAEMONOBJS)
- $(CC) -o $@ $+ $(CFLAGS) $(LIBFLAGS)
+ $(CC) -o $@ $+ $(LINKOPTS)
@$(STRIP) $@
# libdns_sd target builds the client library
CLIENTLIBOBJS = $(OBJDIR)/dnssd_clientlib.c.so.o $(OBJDIR)/dnssd_clientstub.c.so.o $(OBJDIR)/dnssd_ipc.c.so.o
$(BUILDDIR)/libdns_sd.$(LDSUFFIX): $(CLIENTLIBOBJS)
- @$(LD) $(LIBFLAGS) -o $@ $+
+ @$(LD) $(LINKOPTS) -o $@ $+
@$(STRIP) $@
+Clients: setup libdns_sd ../Clients/build/dns-sd
+ @echo "Clients done"
+
+../Clients/build/dns-sd:
+ @$(MAKE) -C ../Clients
+
# nss_mdns target builds the Name Service Switch module
nss_mdns: setup $(BUILDDIR)/$(NSSLIBFILE)
@echo "Name Service Switch module done"
$(BUILDDIR)/$(NSSLIBFILE): $(CLIENTLIBOBJS) $(OBJDIR)/nss_mdns.c.so.o
- @$(LD) $(LIBFLAGS) -o $@ $+
+ @$(LD) $(LINKOPTS) -o $@ $+
@$(STRIP) $@
#############################################################################
InstalledStartup: $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME)
@echo $+ " installed"
-InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8
+InstalledManPages: $(MANPATH)/man8/mdnsd.8
@echo $+ " installed"
-InstalledManPages: $(MANPATH)/man8/mdnsd.8
+InstalledClients: $(INSTBASE)/bin/dns-sd
@echo $+ " installed"
+InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8
+ @echo $+ " installed"
+
+# Note: If daemon already installed, we make sure it's stopped before overwriting it
$(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd
+ @if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi
$(CP) $< $@
$(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
$(INSTBASE)/include/dns_sd.h: $(SHAREDDIR)/dns_sd.h
$(CP) $< $@
-$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR)
+# We make this target dependent on $(INSTBASE)/sbin/mdnsd because we need to ensure
+# that the daemon is installed *before* we try to execute the command to start it.
+$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR) $(INSTBASE)/sbin/mdnsd
$(CP) $< $@
chmod ugo+x $@
+ $@ start
ifdef RUNLEVELSCRIPTSDIR
ifeq ($(wildcard $(RUNLEVELSCRIPTSDIR)/runlevels/default), $(RUNLEVELSCRIPTSDIR)/runlevels/default)
$(LN) $@ $(RUNLEVELSCRIPTSDIR)/runlevels/default/mdns
endif
endif
+$(MANPATH)/man5/%.5: %.5
+ cp $< $@
+ chmod 444 $@
+
+$(MANPATH)/man8/%.8: %.8
+ cp $< $@
+ chmod 444 $@
+
+$(MANPATH)/man8/mdnsd.8: $(SHAREDDIR)/mDNSResponder.8
+ cp $< $@
+ chmod 444 $@
+
+$(INSTBASE)/bin/dns-sd: ../Clients/build/dns-sd
+ $(CP) $< $@
+
$(NSSINSTPATH)/$(NSSLINKNAME): $(NSSINSTPATH)/$(NSSLIBFILE)
$(LN) $< $@
ldconfig
cp -f /etc/nsswitch.conf /etc/nsswitch.conf.pre-mdns
sed -e '/mdns/!s/^\(hosts:.*\)dns\(.*\)/\1mdns dns\2/' /etc/nsswitch.conf.pre-mdns > /etc/nsswitch.conf
-$(MANPATH)/man5/%.5: %.5
- cp $< $@
- chmod 444 $@
-
-$(MANPATH)/man8/%.8: %.8
- cp $< $@
- chmod 444 $@
-
-$(MANPATH)/man8/mdnsd.8: $(SHAREDDIR)/mDNSResponder.8
- cp $< $@
- chmod 444 $@
-
#############################################################################
# The following targets build Java wrappers for the dns-sd.h API.
$(OBJDIR)/com/apple/dnssd/RegisterListener.class \
$(OBJDIR)/com/apple/dnssd/QueryListener.class \
$(OBJDIR)/com/apple/dnssd/DomainListener.class \
+ $(OBJDIR)/com/apple/dnssd/RegisterRecordListener.class \
+ $(OBJDIR)/com/apple/dnssd/DNSSDRecordRegistrar.class \
$(OBJDIR)/com/apple/dnssd/DNSSD.class
-$(BUILDDIR)/dns_sd.jar: $(JARCONTENTS)
+$(BUILDDIR)/dns_sd.jar: $(JARCONTENTS) setup
$(JAR) -cf $@ -C $(OBJDIR) com
-$(BUILDDIR)/libjdns_sd.$(LDSUFFIX): $(JAVASRC)/JNISupport.c $(OBJDIR)/DNSSD.java.h
- $(CC) -o $@ $< $(JAVACFLAGS) -I$(OBJDIR)
+$(BUILDDIR)/libjdns_sd.$(LDSUFFIX): $(JAVASRC)/JNISupport.c $(OBJDIR)/DNSSD.java.h setup libdns_sd
+ $(CC) -o $@ $< $(JAVACFLAGS) -I$(OBJDIR) -L$(BUILDDIR)
$(OBJDIR)/com/apple/dnssd/%.class: $(JAVASRC)/%.java
$(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $<
# The following target builds documentation for the Java wrappers.
-JavaDoc: setup Java
+JavaDoc: Java setup
$(JAVADOC) $(JAVASRC)/*.java -classpath $(OBJDIR) -d $(BUILDDIR) -public
#############################################################################
COMMONOBJ = $(SPECIALOBJ) $(OBJDIR)/mDNS.c.o
APPOBJ = $(COMMONOBJ) $(OBJDIR)/ExampleClientApp.c.o
-Client: setup $(BUILDDIR)/mDNSClientPosix
+SAClient: setup $(BUILDDIR)/mDNSClientPosix
@echo "Embedded Standalone Client done"
-Responder: setup $(BUILDDIR)/mDNSResponderPosix
+SAResponder: setup $(BUILDDIR)/mDNSResponderPosix
@echo "Embedded Standalone Responder done"
-ProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix
+SAProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix
@echo "Embedded Standalone ProxyResponder done"
Identify: setup $(BUILDDIR)/mDNSIdentify
@echo "dnsextd done"
$(BUILDDIR)/mDNSClientPosix: $(APPOBJ) $(OBJDIR)/Client.c.o
- $(CC) $+ -o $@ $(LIBFLAGS)
+ $(CC) $+ -o $@ $(LINKOPTS)
$(BUILDDIR)/mDNSResponderPosix: $(COMMONOBJ) $(OBJDIR)/Responder.c.o
- $(CC) $+ -o $@ $(LIBFLAGS)
+ $(CC) $+ -o $@ $(LINKOPTS)
$(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ) $(OBJDIR)/ProxyResponder.c.o
- $(CC) $+ -o $@ $(LIBFLAGS)
+ $(CC) $+ -o $@ $(LINKOPTS)
$(BUILDDIR)/mDNSIdentify: $(SPECIALOBJ) $(OBJDIR)/Identify.c.o
- $(CC) $+ -o $@ $(LIBFLAGS)
+ $(CC) $+ -o $@ $(LINKOPTS)
+
+$(OBJDIR)/Identify.c.o: $(COREDIR)/mDNS.c # Note: Identify.c textually imports mDNS.c
$(BUILDDIR)/mDNSNetMonitor: $(SPECIALOBJ) $(OBJDIR)/NetMonitor.c.o
- $(CC) $+ -o $@ $(LIBFLAGS)
+ $(CC) $+ -o $@ $(LINKOPTS)
+
+$(OBJDIR)/NetMonitor.c.o: $(COREDIR)/mDNS.c # Note: NetMonitor.c textually imports mDNS.c
-$(BUILDDIR)/dnsextd: $(SPECIALOBJ) $(OBJDIR)/dnsextd.c.threadsafe.o
- $(CC) $+ -o $@ $(LIBFLAGS) -lpthread
+$(BUILDDIR)/dnsextd: $(DNSEXTDOBJ) $(OBJDIR)/dnsextd.c.threadsafe.o
+ $(CC) $+ -o $@ $(LINKOPTS) $(LINKOPTS_PTHREAD)
#############################################################################
$(CC) $(CFLAGS) -c -o $@ $<
$(OBJDIR)/%.c.threadsafe.o: %.c
- $(CC) $(CFLAGS) -D_REENTRANT -c -o $@ $<
+ $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
+
+$(OBJDIR)/%.c.threadsafe.o: $(SHAREDDIR)/%.c
+ $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
$(OBJDIR)/%.c.so.o: %.c
$(CC) $(CFLAGS) -c -fPIC -o $@ $<
$(OBJDIR)/%.c.so.o: $(SHAREDDIR)/%.c
$(CC) $(CFLAGS) -c -fPIC -o $@ $<
+
+$(OBJDIR)/%.y.o: $(SHAREDDIR)/%.y
+ $(BISON) -o $(OBJDIR)/$*.c -d $<
+ $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/$*.c
+
+$(OBJDIR)/%.l.o: $(SHAREDDIR)/%.l
+ $(FLEX) $(FLEXFLAGS_OS) -i -o$(OBJDIR)/$*.l.c $<
+ $(CC) $(CFLAGS) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*
* Formatting notes:
* This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
Change History (most recent first):
$Log: NetMonitor.c,v $
-Revision 1.74 2005/12/02 20:08:39 cheshire
-Update "No HINFO" message
-
-Revision 1.73 2005/12/02 19:19:53 cheshire
-<rdar://problem/4331590> Include interface index and name in mDNSNetMonitor output
-
-Revision 1.72 2005/11/07 01:47:45 cheshire
-<rdar://problem/4331590> Include interface index in mDNSNetMonitor output
-
-Revision 1.71 2004/12/16 20:17:11 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.70 2004/12/04 02:13:20 cheshire
-Pass proper record type in GetLargeResourceRecord() calls
-
-Revision 1.69 2004/11/30 22:37:01 cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.68 2004/10/23 01:16:01 cheshire
-<rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
-
-Revision 1.67 2004/10/16 00:17:00 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.66 2004/09/17 00:31:52 cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.65 2004/09/16 01:58:22 cheshire
-Fix compiler warnings
-
-Revision 1.64 2004/06/15 02:39:47 cheshire
-When displaying error message, only show command name, not entire path
-
-Revision 1.63 2004/05/18 23:51:26 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.62 2004/03/16 18:24:25 cheshire
-If packet destination was not multicast, then display it
-
-Revision 1.61 2004/02/20 09:36:46 cheshire
-Also show TTL in packet header, if it's not 255
-
-Revision 1.60 2004/02/07 02:11:35 cheshire
-Make mDNSNetMonitor smarter about sending targeted unicast HINFO queries
-
-Revision 1.59 2004/02/03 21:42:55 cheshire
-Add constants kReportTopServices and kReportTopHosts
-
-Revision 1.58 2004/01/27 20:15:23 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
-
-Revision 1.57 2004/01/24 23:59:42 cheshire
-Change to use mDNSVal16() instead of shifting and ORing
-
-Revision 1.56 2004/01/24 05:25:34 cheshire
-mDNSNetMonitor now uses the new ability to send unicast queries so that
-it causes less perturbation of the network traffic it's monitoring.
-
-Revision 1.55 2003/12/23 00:21:31 cheshire
-Send HINFO queries to determine the mDNSResponder version of each host
-
-Revision 1.54 2003/12/17 01:06:39 cheshire
-Also show host name along with HINFO data
-
-Revision 1.53 2003/12/17 00:51:22 cheshire
-Changed mDNSNetMonitor and mDNSIdentify to link the object files
-instead of #including the "DNSCommon.c" "uDNS.c" and source files
-
-Revision 1.52 2003/12/17 00:21:51 cheshire
-If we received one, display host's HINFO record in final summary
-
-Revision 1.51 2003/12/13 03:05:28 ksekar
-<rdar://problem/3192548>: DynDNS: Unicast query of service records
-
-Revision 1.50 2003/12/08 20:47:02 rpantos
-Add support for mDNSResponder on Linux.
-
-Revision 1.49 2003/10/30 19:38:56 cheshire
-Fix warning on certain compilers
-
-Revision 1.48 2003/10/30 19:30:00 cheshire
-Fix warnings on certain compilers
-
-Revision 1.47 2003/09/05 18:49:57 cheshire
-Add total packet size to display
-
-Revision 1.46 2003/09/05 02:33:48 cheshire
-Set output to be line buffered, so you can redirect to a file and "tail -f" the file in another window
-
-Revision 1.45 2003/09/04 00:16:20 cheshire
-Only show count of unique source addresses seen on network if we're not filtering
-
-Revision 1.44 2003/09/02 22:13:28 cheshire
-Show total host count in final summary table
-
-Revision 1.43 2003/09/02 21:42:52 cheshire
-Improved alignment of final summary table with v6 addresses
-
-Revision 1.42 2003/09/02 20:59:24 cheshire
-Use bcopy() instead of non-portable "__u6_addr.__u6_addr32" fields.
-
-Revision 1.41 2003/08/29 22:05:44 cheshire
-Also count subsequent KA packets for the purposes of statistics counting
-
-Revision 1.40 2003/08/29 16:43:24 cheshire
-Also display breakdown of Probe/Goodbye/BrowseQ etc. for each host
-
-Revision 1.39 2003/08/28 02:07:48 vlubet
-Added "per hosts" statistics
-
-Revision 1.38 2003/08/20 22:41:42 cheshire
-Also display total multicast packet count
+Revision 1.89 2007/05/17 19:12:42 cheshire
+Tidy up code layout
-Revision 1.37 2003/08/20 22:32:08 cheshire
-Error in DisplayQuery: Authorities come *after* Answers, not before
+Revision 1.88 2007/04/22 20:16:25 cheshire
+Fix compiler errors (const parameter declarations)
-Revision 1.36 2003/08/18 23:20:10 cheshire
-RDLength moved from the RData to the ResourceRecord object.
+Revision 1.87 2007/04/16 20:49:39 cheshire
+Fix compile errors for mDNSPosix build
-Revision 1.35 2003/08/15 20:17:28 cheshire
-"LargeResourceRecord" changed to "LargeCacheRecord"
+Revision 1.86 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-Revision 1.34 2003/08/14 02:19:55 cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+Revision 1.85 2007/02/28 01:51:22 cheshire
+Added comment about reverse-order IP address
-Revision 1.33 2003/08/12 19:56:26 cheshire
-Update to APSL 2.0
+Revision 1.84 2007/01/05 08:30:52 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.32 2003/08/06 18:57:01 cheshire
-Update comments
+Revision 1.83 2006/11/18 05:01:32 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
-Revision 1.31 2003/08/06 02:05:12 cheshire
-Add ability to give a list of hosts to monitor
+Revision 1.82 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.30 2003/08/05 23:56:26 cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-(Right now mDNSPosix.c just reports 255 -- we should fix this)
+Revision 1.81 2006/07/06 00:01:44 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-Revision 1.29 2003/08/05 00:43:12 cheshire
-Report errors encountered while processing authority section
+Revision 1.80 2006/06/12 18:22:42 cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
-Revision 1.28 2003/07/29 22:51:08 cheshire
-Added hexdump for packets we can't decode, so we can find out *why* we couldn't decode them
+Revision 1.79 2006/04/26 20:48:33 cheshire
+Make final count of unique source addresses show IPv4 and IPv6 counts separately
-Revision 1.27 2003/07/29 22:48:04 cheshire
-Completed support for decoding packets containing oversized resource records
+Revision 1.78 2006/04/25 00:42:24 cheshire
+Add ability to specify a single interface index to capture on,
+e.g. typically "-i 4" for Ethernet and "-i 5" for AirPort
-Revision 1.26 2003/07/19 03:25:23 cheshire
-Change to make use of new GetLargeResourceRecord() call, for handling larger records
+Revision 1.77 2006/03/02 21:50:45 cheshire
+Removed strange backslash at the end of a line
-Revision 1.25 2003/07/18 00:13:23 cheshire
-Remove erroneous trailing '\' from TXT record display
+Revision 1.76 2006/02/23 23:38:43 cheshire
+<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
-Revision 1.24 2003/07/17 17:10:51 cheshire
-<rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
-Further work: distinguish between PM and PU
+Revision 1.75 2006/01/05 22:33:58 cheshire
+Use IFNAMSIZ (more portable) instead of IF_NAMESIZE
-Revision 1.23 2003/07/16 22:20:23 cheshire
-<rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
-Made mDNSNetMonitor distinguish between QM and QU in its logging output
-
-Revision 1.22 2003/07/02 21:19:58 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.21 2003/06/18 05:48:41 cheshire
-Fix warnings
-
-Revision 1.20 2003/06/06 22:18:22 cheshire
-Add extra space in Q output to line it up with RR output
-
-Revision 1.19 2003/06/06 21:05:04 cheshire
-Display state of cache-flush bit on additional records
-
-Revision 1.18 2003/06/06 20:01:30 cheshire
-For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
-(Global search-and-replace; no functional change to code execution.)
-
-Revision 1.17 2003/06/06 14:26:50 cheshire
-Explicitly #include <time.h> for the benefit of certain Linux distributions
-
-Revision 1.16 2003/05/29 21:56:36 cheshire
-More improvements:
-Distinguish modern multicast queries from legacy multicast queries
-In addition to record counts, display packet counts of queries, legacy queries, and responses
-Include TTL in RR display
-
-Revision 1.15 2003/05/29 20:03:57 cheshire
-Various improvements:
-Display start and end time, average rates in packets-per-minute,
-show legacy queries as -LQ-, improve display of TXT and unknown records
-
-Revision 1.14 2003/05/26 04:45:42 cheshire
-Limit line length when printing super-long TXT records
-
-Revision 1.13 2003/05/26 03:21:29 cheshire
-Tidy up address structure naming:
-mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.12 2003/05/26 03:01:28 cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.11 2003/05/26 00:48:13 cheshire
-If mDNS packet contains a non-zero message ID, then display it.
-
-Revision 1.10 2003/05/22 01:10:32 cheshire
-Indicate when the TC bit is set on a query packet
-
-Revision 1.9 2003/05/21 03:56:00 cheshire
-Improve display of Probe queries
-
-Revision 1.8 2003/05/09 21:41:56 cheshire
-Track deletion/goodbye packets as separate category
-
-Revision 1.7 2003/05/07 00:16:01 cheshire
-More detailed decoding of Resource Records
-
-Revision 1.6 2003/05/05 21:16:16 cheshire
-<rdar://problem/3241281> Change timenow from a local variable to a structure member
-
-Revision 1.5 2003/04/19 01:16:22 cheshire
-Add filter option, to monitor only packets from a single specified source address
-
-Revision 1.4 2003/04/18 00:45:21 cheshire
-Distinguish announcements (AN) from deletions (DE)
-
-Revision 1.3 2003/04/15 18:26:01 cheshire
-Added timestamps and help information
-
-Revision 1.2 2003/04/04 20:42:02 cheshire
-Fix broken statistics counting
-
-Revision 1.1 2003/04/04 01:37:14 cheshire
-Added NetMonitor.c
-
- */
+*/
//*************************************************************************************************************
// Incorporate mDNS.c functionality
#include <signal.h> // For SIGINT, SIGTERM
#include <netdb.h> // For gethostbyname()
#include <sys/socket.h> // For AF_INET, AF_INET6, etc.
-#include <arpa/inet.h> // For inet_addr()
#include <net/if.h> // For IF_NAMESIZE
#include <netinet/in.h> // For INADDR_NONE
+#include <arpa/inet.h> // For inet_addr()
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
#include "ExampleClientApp.h"
static mDNS mDNSStorage; // mDNS core uses this to store its globals
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
+mDNSexport const char ProgramName[] = "mDNSNetMonitor";
struct timeval tv_start, tv_end, tv_interval;
-
+static int FilterInterface = 0;
static FilterList *Filters;
#define ExactlyOneFilter (Filters && !Filters->next)
static HostList IPv4HostList = { 0, 0, 0 };
static HostList IPv6HostList = { 0, 0, 0 };
-mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList* list)
+mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList *list)
{
long i;
return NULL;
}
-mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList* list)
+mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList *list)
{
int i;
HostEntry *entry;
{
mDNSv4Addr ip = entry->addr.ip.v4;
char buffer[32];
+ // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", ip.b[3], ip.b[2], ip.b[1], ip.b[0]);
MakeDomainNameFromDNSNameString(&entry->revname, buffer);
}
if (sw + 1 + sw[0] <= rdend)
{
AssignDomainName(&entry->hostname, pktrr->name);
- mDNSPlatformMemCopy(hw, entry->HIHardware.c, 1 + (mDNSu32)hw[0]);
- mDNSPlatformMemCopy(sw, entry->HISoftware.c, 1 + (mDNSu32)sw[0]);
+ mDNSPlatformMemCopy(entry->HIHardware.c, hw, 1 + (mDNSu32)hw[0]);
+ mDNSPlatformMemCopy(entry->HISoftware.c, sw, 1 + (mDNSu32)sw[0]);
}
}
}
{
//mprintf("%#a Q\n", target);
InterfaceID = mDNSInterface_Any; // Send query from our unicast reply socket
- m->ExpectUnicastResponse = m->timenow;
}
- mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, -1, mDNSNULL);
+ mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, mDNSNULL, mDNSNULL);
}
mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
if (e->pkts[HostPkt_B]) mprintf("Bad: %8lu", e->pkts[HostPkt_B]);
mprintf("\n");
if (!e->HISoftware.c[0] && e->NumQueries > 2)
- mDNSPlatformMemCopy("\x27*** Unknown (Jaguar, Windows, etc.) ***", &e->HISoftware, 0x28);
+ mDNSPlatformMemCopy(&e->HISoftware, "\x27*** Unknown (Jaguar, Windows, etc.) ***", 0x28);
if (e->hostname.c[0] || e->HIHardware.c[0] || e->HISoftware.c[0])
mprintf("%##-45s %#-14s %#s\n", e->hostname.c, e->HIHardware.c, e->HISoftware.c);
}
return(mDNStrue);
}
-mDNSlocal void recordstat(HostEntry *entry, domainname *fqdn, int op, mDNSu16 rrtype)
+mDNSlocal void recordstat(HostEntry *entry, const domainname *fqdn, int op, mDNSu16 rrtype)
{
ActivityStat **s = &stats;
domainname srvtype;
}
}
-mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end,\
+mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end,
DNSQuestion *q, LargeCacheRecord *pkt)
{
int i;
struct timeval tv;
struct tm tm;
const mDNSu32 index = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID);
- char if_name[IF_NAMESIZE];
+ char if_name[IFNAMSIZ]; // Older Linux distributions don't define IF_NAMESIZE
if_indextoname(index, if_name);
gettimeofday(&tv, NULL);
localtime_r((time_t*)&tv.tv_sec, &tm);
const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
const mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
+ int goodinterface = (FilterInterface == 0);
(void)dstaddr; // Unused
(void)dstport; // Unused
// For now we're only interested in monitoring IPv4 traffic.
// All IPv6 packets should just be duplicates of the v4 packets.
- if (AddressMatchesFilterList(srcaddr))
+ if (!goodinterface) goodinterface = (FilterInterface == (int)mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID));
+ if (goodinterface && AddressMatchesFilterList(srcaddr))
{
mDNS_Lock(m);
if (!mDNSAddrIsDNSMulticast(dstaddr))
localtime_r((time_t*)&tv_end.tv_sec, &tm);
mprintf("End %3d:%02d:%02d.%06d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tv_end.tv_usec);
mprintf("Captured for %3d:%02d:%02d.%06d\n", h, m, s, tv_interval.tv_usec);
- if (!Filters) mprintf("Unique source addresses seen on network: %ld\n", IPv4HostList.num + IPv6HostList.num);
+ if (!Filters)
+ {
+ mprintf("Unique source addresses seen on network:");
+ if (IPv4HostList.num) mprintf(" %ld (IPv4)", IPv4HostList.num);
+ if (IPv6HostList.num) mprintf(" %ld (IPv6)", IPv6HostList.num);
+ if (!IPv4HostList.num && !IPv6HostList.num) mprintf(" None");
+ mprintf("\n");
+ }
mprintf("\n");
mprintf("Modern Query Packets: %7d (avg%5d/min)\n", NumPktQ, NumPktQ * mul / div);
mprintf("Legacy Query Packets: %7d (avg%5d/min)\n", NumPktL, NumPktL * mul / div);
for (i=1; i<argc; i++)
{
- struct in_addr s4;
- struct in6_addr s6;
- FilterList *f;
- mDNSAddr a;
- a.type = mDNSAddrType_IPv4;
-
- if (inet_pton(AF_INET, argv[i], &s4) == 1)
- a.ip.v4.NotAnInteger = s4.s_addr;
- else if (inet_pton(AF_INET6, argv[i], &s6) == 1)
+ if (i+1 < argc && !strcmp(argv[i], "-i") && atoi(argv[i+1]))
{
- a.type = mDNSAddrType_IPv6;
- bcopy(&s6, &a.ip.v6, sizeof(a.ip.v6));
+ FilterInterface = atoi(argv[i+1]);
+ i += 2;
+ printf("Monitoring interface %d\n", FilterInterface);
}
else
{
- struct hostent *h = gethostbyname(argv[i]);
- if (h) a.ip.v4.NotAnInteger = *(long*)h->h_addr;
- else goto usage;
+ struct in_addr s4;
+ struct in6_addr s6;
+ FilterList *f;
+ mDNSAddr a;
+ a.type = mDNSAddrType_IPv4;
+
+ if (inet_pton(AF_INET, argv[i], &s4) == 1)
+ a.ip.v4.NotAnInteger = s4.s_addr;
+ else if (inet_pton(AF_INET6, argv[i], &s6) == 1)
+ {
+ a.type = mDNSAddrType_IPv6;
+ bcopy(&s6, &a.ip.v6, sizeof(a.ip.v6));
+ }
+ else
+ {
+ struct hostent *h = gethostbyname(argv[i]);
+ if (h) a.ip.v4.NotAnInteger = *(long*)h->h_addr;
+ else goto usage;
+ }
+
+ f = malloc(sizeof(*f));
+ f->FilterAddr = a;
+ f->next = Filters;
+ Filters = f;
}
-
- f = malloc(sizeof(*f));
- f->FilterAddr = a;
- f->next = Filters;
- Filters = f;
}
status = mDNSNetMonitor();
- if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %ld\n", progname, status); return(status); }
+ if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %d\n", progname, (int)status); return(status); }
return(0);
usage:
*
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
File: daemon.c
Change History (most recent first):
$Log: PosixDaemon.c,v $
-Revision 1.29 2005/08/04 03:37:45 mkrochma
-Temporary workaround to fix posix after mDNS_SetPrimaryInterfaceInfo changed
-
-Revision 1.28 2005/07/19 11:21:09 cheshire
-<rdar://problem/4170449> Unix Domain Socket leak in mdnsd
-
-Revision 1.27 2005/02/04 00:39:59 cheshire
-Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
-
-Revision 1.26 2005/02/02 02:21:30 cheshire
-Update references to "mDNSResponder" to say "mdnsd" instead
-
-Revision 1.25 2005/01/27 20:01:50 cheshire
-udsSupportRemoveFDFromEventLoop() needs to close the file descriptor as well
-
-Revision 1.24 2005/01/19 19:20:49 ksekar
-<rdar://problem/3960191> Need a way to turn off domain discovery
-
-Revision 1.23 2004/12/16 20:17:11 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.22 2004/12/10 13:12:08 cheshire
-Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
-
-Revision 1.21 2004/12/01 20:57:20 ksekar
-<rdar://problem/3873921> Wide Area Service Discovery must be split-DNS aware
-
-Revision 1.20 2004/12/01 04:28:43 cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Use version of daemon() provided in mDNSUNP.c instead of local copy
-
-Revision 1.19 2004/12/01 03:30:29 cheshire
-<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
+Revision 1.42 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-Revision 1.18 2004/11/30 22:45:59 cheshire
-Minor code tidying
+Revision 1.41 2007/09/04 17:02:25 cheshire
+<rdar://problem/5458929> False positives in changed files list in nightly builds
+Added MDNS_VERSIONSTR_NODTS option at the reqest of Rishi Srivatsavai (Sun)
-Revision 1.17 2004/11/30 22:18:59 cheshire
-<rdar://problem/3889351> Posix needs to read the list of unicast DNS servers and set server list
+Revision 1.40 2007/07/31 23:08:34 mcguire
+<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
-Revision 1.16 2004/09/21 21:05:12 cheshire
-Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
-into mDNSShared/uds_daemon.c
+Revision 1.39 2007/03/21 00:30:44 cheshire
+Remove obsolete mDNS_DeleteDNSServers() call
-Revision 1.15 2004/09/17 01:08:53 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.38 2007/02/14 01:58:19 cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-Revision 1.14 2004/09/16 00:24:49 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.37 2007/02/07 19:32:00 cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-Revision 1.13 2004/08/11 01:59:41 cheshire
-Remove "mDNS *globalInstance" parameter from udsserver_init()
+Revision 1.36 2007/02/06 19:06:48 cheshire
+<rdar://problem/3956518> Need to go native with launchd
-Revision 1.12 2004/06/28 23:19:19 cheshire
-Fix "Daemon_Init declared but never defined" warning on Linux
+Revision 1.35 2007/01/05 08:30:52 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.11 2004/06/25 00:26:27 rpantos
-Changes to fix the Posix build on Solaris.
+Revision 1.34 2007/01/05 05:46:08 cheshire
+Add mDNS *const m parameter to udsserver_handle_configchange()
-Revision 1.10 2004/06/08 04:59:40 cheshire
-Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it
+Revision 1.33 2006/12/21 00:10:53 cheshire
+Make mDNS_PlatformSupport PlatformStorage a static global instead of a stack variable
-Revision 1.9 2004/05/29 00:14:20 rpantos
-<rdar://problem/3508093> Runtime check to disable prod mdnsd on OS X.
+Revision 1.32 2006/11/03 22:28:50 cheshire
+PosixDaemon needs to handle mStatus_ConfigChanged and mStatus_GrowCache messages
-Revision 1.8 2004/04/07 01:19:04 cheshire
-Hash slot value should be unsigned
+Revision 1.31 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.7 2004/02/14 06:34:57 cheshire
-Use LogMsg instead of fprintf( stderr
+Revision 1.30 2006/07/07 01:09:12 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-Revision 1.6 2004/02/14 01:10:42 rpantos
-Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.)
-
-Revision 1.5 2004/02/05 07:45:43 cheshire
-Add Log header
-
-Revision 1.4 2004/01/28 21:14:23 cheshire
-Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
-
-Revision 1.3 2004/01/19 19:51:46 cheshire
-Fix compiler error (mixed declarations and code) on some versions of Linux
-
-Revision 1.2 2003/12/11 03:03:51 rpantos
-Clean up mDNSPosix so that it builds on OS X again.
-
-Revision 1.1 2003/12/08 20:47:02 rpantos
-Add support for mDNSResponder on Linux.
*/
#include <stdio.h>
#define RR_CACHE_SIZE 500
static CacheEntity gRRCache[RR_CACHE_SIZE];
+static mDNS_PlatformSupport PlatformStorage;
+
+mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
+ {
+ (void)m; // Unused
+ if (result == mStatus_NoError)
+ {
+ // On successful registration of dot-local mDNS host name, daemon may want to check if
+ // any name conflict and automatic renaming took place, and if so, record the newly negotiated
+ // name in persistent storage for next time. It should also inform the user of the name change.
+ // On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store,
+ // and notify the user with a CFUserNotification.
+ }
+ else if (result == mStatus_ConfigChanged)
+ {
+ udsserver_handle_configchange(m);
+ }
+ else if (result == mStatus_GrowCache)
+ {
+ // Allocate another chunk of cache storage
+ CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE);
+ if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
+ }
+ }
-extern const char mDNSResponderVersionString[];
+// %%% Reconfigure() probably belongs in the platform support layer (mDNSPosix.c), not the daemon cde
+// -- all client layers running on top of mDNSPosix.c need to handle network configuration changes,
+// not only the Unix Domain Socket Daemon
static void Reconfigure(mDNS *m)
{
mDNSAddr DynDNSIP;
mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL);
- mDNS_DeleteDNSServers(m);
if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
- FindDefaultRouteIP(&DynDNSIP);
+ FindSourceAddrForIP(NULL, &DynDNSIP);
if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL);
+ m->MainCallback(m, mStatus_ConfigChanged);
}
// Do appropriate things at startup with command line arguments. Calls exit() if unhappy.
-static void ParseCmdLinArgs(int argc, char **argv)
+mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
{
if (argc > 1)
{
}
}
-static void DumpStateLog(mDNS *const m)
+mDNSlocal void DumpStateLog(mDNS *const m)
// Dump a little log of what we've been up to.
{
LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----");
}
-static mStatus MainLoop(mDNS *m) // Loop until we quit.
+mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
{
sigset_t signals;
mDNSBool gotData = mDNSfalse;
return EINTR;
}
-int main(int argc, char **argv)
+int main(int argc, char **argv)
{
- #define mDNSRecord mDNSStorage
- mDNS_PlatformSupport platformStorage;
mStatus err;
- bzero(&mDNSRecord, sizeof mDNSRecord);
- bzero(&platformStorage, sizeof platformStorage);
-
ParseCmdLinArgs(argc, argv);
LogMsgIdent(mDNSResponderVersionString, "starting");
- err = mDNS_Init(&mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
- mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
+ err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses,
+ mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
if (mStatus_NoError == err)
- err = udsserver_init();
+ err = udsserver_init(dnssd_InvalidSocket);
- Reconfigure(&mDNSRecord);
+ Reconfigure(&mDNSStorage);
// Now that we're finished with anything privileged, switch over to running as "nobody"
if (mStatus_NoError == err)
}
if (mStatus_NoError == err)
- err = MainLoop(&mDNSRecord);
+ err = MainLoop(&mDNSStorage);
LogMsgIdent(mDNSResponderVersionString, "stopping");
- mDNS_Close(&mDNSRecord);
+ mDNS_Close(&mDNSStorage);
- if (udsserver_exit() < 0)
+ if (udsserver_exit(dnssd_InvalidSocket) < 0)
LogMsg("ExitCallback: udsserver_exit failed");
#if MDNS_DEBUGMSGS > 0
// uds_daemon support ////////////////////////////////////////////////////////////
-#if MDNS_MALLOC_DEBUGGING >= 2
-#define LogMalloc LogMsg
-#else
-#define LogMalloc(ARGS...) ((void)0)
-#endif
-
mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
/* Support routine for uds_daemon.c */
{
// No-op, for now
}
-#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
-
-void *mallocL(char *msg, unsigned int size)
- {
- unsigned long *mem = malloc(size+8);
- if (!mem)
- {
- LogMsg("malloc( %s : %d ) failed", msg, size);
- return(NULL);
- }
- else
- {
- LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
- mem[0] = 0xDEAD1234;
- mem[1] = size;
- //bzero(&mem[2], size);
- memset(&mem[2], 0xFF, size);
-// validatelists(&mDNSStorage);
- return(&mem[2]);
- }
- }
-
-void freeL(char *msg, void *x)
- {
- if (!x)
- LogMsg("free( %s @ NULL )!", msg);
- else
- {
- unsigned long *mem = ((unsigned long *)x) - 2;
- if (mem[0] != 0xDEAD1234)
- { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
- if (mem[1] > 8000)
- { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; }
- LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
- //bzero(mem, mem[1]+8);
- memset(mem, 0xDD, mem[1]+8);
-// validatelists(&mDNSStorage);
- free(mem);
- }
- }
-
-#endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
// For convenience when using the "strings" command, this is the last thing in the file
#if mDNSResponderVersion > 1
-mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") ";
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+#elif MDNS_VERSIONSTR_NODTS
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)";
#else
-mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") ";
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ")";
#endif
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ProxyResponder.c,v $
+Revision 1.44 2007/04/22 20:16:25 cheshire
+Fix compiler errors (const parameter declarations)
+
+Revision 1.43 2007/04/16 20:49:39 cheshire
+Fix compile errors for mDNSPosix build
+
+Revision 1.42 2007/03/06 22:45:53 cheshire
+
+<rdar://problem/4138615> argv buffer overflow issues
+
+Revision 1.41 2007/02/28 01:51:22 cheshire
+Added comment about reverse-order IP address
+
+Revision 1.40 2007/01/05 04:32:13 cheshire
+Change "(domainname *)" cast to "(const domainname *)"
+
+Revision 1.39 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.38 2006/06/12 18:22:42 cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
+
+Revision 1.37 2006/02/23 23:38:43 cheshire
+<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
+
Revision 1.36 2005/08/04 03:12:47 mkrochma
<rdar://problem/4199236> Register reverse PTR record using multicast
#include <unistd.h> // For select()
#include <signal.h> // For SIGINT, SIGTERM
#include <errno.h> // For errno, EINTR
-#include <arpa/inet.h> // For inet_addr()
#include <netinet/in.h> // For INADDR_NONE
+#include <arpa/inet.h> // For inet_addr()
#include <netdb.h> // For gethostbyname()
#include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
// Globals
static mDNS mDNSStorage; // mDNS core uses this to store its globals
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
+mDNSexport const char ProgramName[] = "mDNSProxyResponderPosix";
//*************************************************************************************************************
// Proxy Host Registration
mDNS_SetupResourceRecord(&p->RR_A, mDNSNULL, mDNSInterface_Any, kDNSType_A, 60, kDNSRecordTypeUnique, HostNameCallback, p);
mDNS_SetupResourceRecord(&p->RR_PTR, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, HostNameCallback, p);
- p->RR_A.resrec.name->c[0] = 0;
- AppendDomainLabel(p->RR_A.resrec.name, &p->hostlabel);
- AppendLiteralLabelString(p->RR_A.resrec.name, "local");
+ p->RR_A.namestorage.c[0] = 0;
+ AppendDomainLabel(&p->RR_A.namestorage, &p->hostlabel);
+ AppendLiteralLabelString(&p->RR_A.namestorage, "local");
+ // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
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]);
- MakeDomainNameFromDNSNameString(p->RR_PTR.resrec.name, buffer);
+ MakeDomainNameFromDNSNameString(&p->RR_PTR.namestorage, buffer);
p->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
p->RR_A. resrec.rdata->u.ipv4 = p->ip;
while (argc)
{
int len = strlen(argv[0]);
+ if (len > 255 || bptr + 1 + len >= txtbuffer + sizeof(txtbuffer)) break;
printf("STR: %s\n", argv[0]);
bptr[0] = len;
strcpy((char*)(bptr+1), argv[0]);
mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
- domainname *proxyhostname = (domainname *)rr->RecordContext;
+ const domainname *proxyhostname = (const domainname *)rr->RecordContext;
switch (result)
{
case mStatus_NoError: debugf("Callback: %##s Name Registered", rr->resrec.name->c); break;
mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
mDNS_Init_DontAdvertiseLocalAddresses,
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
- if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); }
+ if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); }
mDNSPosixListenForSignalInEventLoop(SIGINT);
mDNSPosixListenForSignalInEventLoop(SIGTERM);
ReadMe About mDNSPosix
----------------------
-mDNSPosix is a port of Apple's core mDNS code to Posix platforms.
+mDNSPosix is a port of Apple's Multicast DNS and DNS Service Discovery
+code to Posix platforms.
-mDNS is short for "multicast DNS", which is a technology that allows you
-to register IP services and browse the network for those services. For
-more information about mDNS, see the mDNS web site.
+Multicast DNS and DNS Service Discovery are technologies that allow you
+to register IP-based services and browse the network for those services.
+For more information about mDNS, see the mDNS web site.
<http://www.multicastdns.org/>
-mDNS is part of a family of technologies resulting from the efforts of
-the IETF zeroconf working group. For information about other zeroconf
-technologies, see the zeroconf web site.
+Multicast DNS is part of a family of technologies resulting from the
+efforts of the IETF Zeroconf working group. For information about
+other Zeroconf technologies, see the Zeroconf web site.
<http://www.zeroconf.org/>
Apple uses the trade mark "Bonjour" to describe our implementation of
-zeroconf technologies. This sample is designed to show how easy it is
+Zeroconf technologies. This sample is designed to show how easy it is
to make a device "Bonjour compatible".
+The "Bonjour" trade mark can also be licensed at no charge for
+inclusion on your own products, packaging, manuals, promotional
+materials, or web site. For details and licensing terms, see
+
+ <http://developer.apple.com/bonjour/>
+
The code in this sample was compiled and tested on Mac OS X (10.1.x,
10.2, 10.3), Solaris (SunOS 5.8), Linux (Redhat 2.4.9-21, Fedora Core 1),
and OpenBSD (2.9). YMMV.
- mDNSResponderPosix
- mDNSProxyResponderPosix
-o Debugging tools
+o Testing and Debugging tools
+ - dns-sd command-line tool (from the "Clients" folder)
- mDNSNetMonitor
- mDNSIdentify
-As root type "make install" to install six things:
+As root type "make install" to install eight things:
o mdnsd (usually in /usr/sbin)
o libmdns (usually in /usr/lib)
o dns_sd.h (usually in /usr/include)
o startup scripts (e.g. in /etc/rc.d)
o manual pages (usually in /usr/share/man)
+o dns-sd tool (usually in /usr/bin)
o nss_mdns (usually in /lib)
o nss configuration files (usually in /etc)
-Once you've installed the files in their respective places,
-you need to start the daemon running, either by rebooting,
-or by running the startup script "/etc/init.d/mdns start"
-(the exact path may be different on your system).
-Then you can cd to the "Clients" folder and type "make".
-This builds a test client showing how to exercise all the major
-functionality of the daemon.
+The "make install" concludes by executing the startup script
+(usually "/etc/init.d/mdns start") to start the daemon running.
+You shouldn't need to reboot unless you really want to.
+
+Once the daemon is running, you can use the dns-sd test tool
+to exercise all the major functionality of the daemon. Running
+"dns-sd" with no arguments gives a summary of the available options.
+This test tool is also described in detail, with several examples,
+in Chapter 6 of the O'Reilly "Zero Configuration Networking" book.
How It Works
-------
Currently the program uses a simple make file.
-There are various problems with loopback-only self discovery. The code
-will attempt service discovery on the loopback interface only if no
-other interfaces are available. However, this exposes a number of
-problems with the underlying network stack (at least on Mac OS X).
+The Multicast DNS protocol can also operate locally over the loopback
+interface, but this exposed some problems with the underlying network
+stack in early versions of Mac OS X and may expose problems with other
+network stacks too.
-o On Mac OS X 10.1.x the code fails to start on the loopback interface
+o On Mac OS X 10.1.x the code failed to start on the loopback interface
because the IP_ADD_MEMBERSHIP option returns ENOBUFS.
-o On Mac OS X 10.2 the loopback-only case fails because
- mDNSPlatformSendUDP's call to "sendto" fails with error EHOSTUNREACH
- [Radar ID 3016042].
+o On Mac OS X 10.2 the loopback-only case failed because
+ "sendto" calls fails with error EHOSTUNREACH. (3016042)
+
+Consequently, the code will attempt service discovery on the loopback
+interface only if no other interfaces are available.
I haven't been able to test the loopback-only case on other platforms
because I don't have access to the physical machine.
Licencing
---------
-This code is distributed under the Apple Public Source License.
-Information about the licence is included at the top of each source file.
-
+This source code is Open Source; for details see the "LICENSE" file.
Credits and Version History
---------------------------
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Responder.c,v $
+Revision 1.33 2007/04/16 20:49:39 cheshire
+Fix compile errors for mDNSPosix build
+
+Revision 1.32 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.31 2006/06/12 18:22:42 cheshire
+<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
+
Revision 1.30 2005/10/26 22:21:16 cheshire
<rdar://problem/4149841> Potential buffer overflow in mDNSResponderPosix
static mDNS mDNSStorage; // mDNS core uses this to store its globals
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
-static const char *gProgramName = "mDNSResponderPosix";
+mDNSexport const char ProgramName[] = "mDNSResponderPosix";
+
+static const char *gProgramName = ProgramName;
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark ***** Signals
result = 2;
}
if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) {
- fprintf(stderr, "%s: Finished with status %ld, result %d\n", gProgramName, status, result);
+ fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result);
}
return result;
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: dnsextd.c,v $
-Revision 1.33.2.1 2005/08/05 21:14:00 ksekar
-<rdar://problem/4012279> Long-lived queries not working on windows
-Change constant names
-
-Revision 1.33 2005/03/11 19:09:02 ksekar
-Fixed ZERO_LLQID macro
-
-Revision 1.32 2005/03/10 22:54:33 ksekar
-<rdar://problem/4046285> dnsextd leaks memory/ports
-
-Revision 1.31 2005/02/24 02:37:57 ksekar
-<rdar://problem/4021977> dnsextd memory management improvements
-
-Revision 1.30 2005/01/27 22:57:56 cheshire
-Fix compile errors on gcc4
-
-Revision 1.29 2004/12/22 00:13:50 ksekar
-<rdar://problem/3873993> Change version, port, and polling interval for LLQ
-
-Revision 1.28 2004/12/17 00:30:00 ksekar
-<rdar://problem/3924045> dnsextd memory leak
-
-Revision 1.27 2004/12/17 00:27:32 ksekar
-Ignore SIGPIPE
-
-Revision 1.26 2004/12/17 00:21:33 ksekar
-Fixes for new CacheRecord structure with indirect name pointer
-
-Revision 1.25 2004/12/16 20:13:02 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.24 2004/12/14 17:09:06 ksekar
-fixed incorrect usage instructions
-
-Revision 1.23 2004/12/06 20:24:31 ksekar
-<rdar://problem/3907303> dnsextd leaks sockets
-
-Revision 1.22 2004/12/03 20:20:29 ksekar
-<rdar://problem/3904149> dnsextd: support delivery of large records via LLQ events
-
-Revision 1.21 2004/12/03 06:11:34 ksekar
-<rdar://problem/3885059> clean up dnsextd arguments
-
-Revision 1.20 2004/12/01 04:27:28 cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
-
-Revision 1.19 2004/12/01 01:16:29 cheshire
-Solaris compatibility fixes
-
-Revision 1.18 2004/11/30 23:51:06 cheshire
-Remove double semicolons
-
-Revision 1.17 2004/11/30 22:37:01 cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.16 2004/11/25 02:02:28 ksekar
-Fixed verbose log message argument
-
-Revision 1.15 2004/11/19 02:35:02 ksekar
-<rdar://problem/3886317> Wide Area Security: Add LLQ-ID to events
-
-Revision 1.14 2004/11/17 06:17:58 cheshire
-Update comments to show correct SRV names: _dns-update._udp.<zone>. and _dns-llq._udp.<zone>.
-
-Revision 1.13 2004/11/13 02:22:36 ksekar
-<rdar://problem/3878201> Refresh Acks from daemon malformatted
-
-Revision 1.12 2004/11/12 01:05:01 ksekar
-<rdar://problem/3876757> dnsextd: daemon registers the SRV same record
-twice at startup
-
-Revision 1.11 2004/11/12 01:03:31 ksekar
-<rdar://problem/3876776> dnsextd: KnownAnswers (CacheRecords) leaked
-
-Revision 1.10 2004/11/12 00:35:28 ksekar
-<rdar://problem/3876705> dnsextd: uninitialized pointer can cause crash
-
-Revision 1.9 2004/11/10 20:38:17 ksekar
-<rdar://problem/3874168> dnsextd: allow a "fudge" in LLQ lease echo
-
-Revision 1.8 2004/11/01 17:48:14 cheshire
-Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but
-it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page
-137. Since C doesn't have a modular type, we used signed, C's closest approximation.
-
-Revision 1.7 2004/10/30 00:06:58 ksekar
-<rdar://problem/3722535> Support Long Lived Queries in DNS Extension daemon
-
-Revision 1.6 2004/09/17 01:08:54 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.5 2004/09/16 00:50:54 cheshire
-Don't use MSG_WAITALL -- it returns "Invalid argument" on some Linux versions
-
-Revision 1.4 2004/09/14 23:27:48 cheshire
-Fix compile errors
-
-Revision 1.3 2004/09/02 01:39:40 cheshire
-For better readability, follow consistent convention that QR bit comes first, followed by OP bits
-
-Revision 1.2 2004/08/24 23:27:57 cheshire
-Fixes for Linux compatibility:
-Don't use strings.h
-Don't assume SIGINFO
-Don't try to set servaddr.sin_len on platforms that don't have sa_len
-
-Revision 1.1 2004/08/11 00:43:26 ksekar
-<rdar://problem/3722542>: DNS Extension daemon for DNS Update Lease
-
-*/
-
-#include "../mDNSCore/mDNSEmbeddedAPI.h"
-#include "../mDNSCore/DNSCommon.h"
-#include "../mDNSCore/mDNS.c"
-//!!!KRS we #include mDNS.c for the various constants defined there - we should move these to DNSCommon.h
-
-#include <signal.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <syslog.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-#include <errno.h>
-
-// Compatibility workaround
-#ifndef AF_LOCAL
-#define AF_LOCAL AF_UNIX
-#endif
-
-//
-// Constants
-//
-
-#define LOOPBACK "127.0.0.1"
-#define NS_PORT 53
-#define DAEMON_PORT 5352 // default, may be overridden via command line argument
-#define LISTENQ 128 // tcp connection backlog
-#define RECV_BUFLEN 9000
-#define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
-#define LLQ_TABLESIZE 1024 // !!!KRS make this dynamically growable
-#define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
-#define SRV_TTL 7200 // TTL For _dns-update SRV records
-
-// LLQ Lease bounds (seconds)
-#define LLQ_MIN_LEASE (15 * 60)
-#define LLQ_MAX_LEASE (120 * 60)
-#define LLQ_LEASE_FUDGE 60
-
-// LLQ SOA poll interval (microseconds)
-#define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
-#define LLQ_MONITOR_INTERVAL 250000
-#ifdef SIGINFO
-#define INFO_SIGNAL SIGINFO
-#else
-#define INFO_SIGNAL SIGUSR1
-#endif
-
-#define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
-#define ZERO_LLQID(x) (!memcmp(x, "\x0\x0\x0\x0\x0\x0\x0\x0", 8))
-
-//
-// Data Structures
-// Structs/fields that must be locked for thread safety are explicitly commented
-//
-
-typedef struct
- {
- struct sockaddr_in src;
- size_t len;
- DNSMessage msg;
- // Note: extra storage for oversized (TCP) messages goes here
- } PktMsg;
-
-// lease table entry
-typedef struct RRTableElem
- {
- struct RRTableElem *next;
- struct sockaddr_in cli; // client's source address
- long expire; // expiration time, in seconds since epoch
- domainname zone; // from zone field of update message
- domainname name; // name of the record
- CacheRecord rr; // last field in struct allows for allocation of oversized RRs
- } RRTableElem;
-
-typedef enum
- {
- RequestReceived = 0,
- ChallengeSent = 1,
- Established = 2
- } LLQState;
-
-typedef struct AnswerListElem
- {
- struct AnswerListElem *next;
- domainname name;
- mDNSu16 type;
- CacheRecord *KnownAnswers; // All valid answers delivered to client
- CacheRecord *EventList; // New answers (adds/removes) to be sent to client
- int refcount;
- } AnswerListElem;
-
-// llq table entry
-typedef struct LLQEntry
- {
- struct LLQEntry *next;
- struct sockaddr_in cli; // clien'ts source address
- domainname qname;
- mDNSu16 qtype;
- mDNSu8 id[8];
- LLQState state;
- mDNSu32 lease; // original lease, in seconds
- mDNSs32 expire; // expiration, absolute, in seconds since epoch
- AnswerListElem *AnswerList;
- } LLQEntry;
-
-// daemon-wide information
-typedef struct
- {
- // server variables - read only after initialization (no locking)
- struct in_addr saddr; // server address
- domainname zone; // zone being updated
- int tcpsd; // listening TCP socket
- int udpsd; // listening UDP socket
-
- // daemon variables - read only after initialization (no locking)
- uDNS_AuthInfo *AuthInfo; // linked list of keys for signing deletion updates
- mDNSIPPort port; // listening port
-
- // lease table variables (locked via mutex after initialization)
- RRTableElem **table; // hashtable for records with leases
- pthread_mutex_t tablelock; // mutex for lease table
- mDNSs32 nbuckets; // buckets allocated
- mDNSs32 nelems; // elements in table
-
- // LLQ table variables
- LLQEntry *LLQTable[LLQ_TABLESIZE]; // !!!KRS change this and RRTable to use a common data structure
- AnswerListElem *AnswerTable[LLQ_TABLESIZE];
- int LLQEventListenSock; // Unix domain socket pair - polling thread writes to ServPollSock, which wakes
- int LLQServPollSock; // the main thread listening on EventListenSock, indicating that the zone has changed
- } DaemonInfo;
-
-// args passed to UDP request handler thread as void*
-typedef struct
- {
- PktMsg pkt;
- struct sockaddr_in cliaddr;
- DaemonInfo *d;
- } UDPRequestArgs;
-
-// args passed to TCP request handler thread as void*
-typedef struct
- {
- int sd; // socket connected to client
- struct sockaddr_in cliaddr;
- DaemonInfo *d;
- } TCPRequestArgs;
-
-//
-// Global Variables
-//
-
-// booleans to determine runtime output
-// read-only after initialization (no mutex protection)
-static mDNSBool foreground = 0;
-static mDNSBool verbose = 0;
-
-// globals set via signal handler (accessed exclusively by main select loop and signal handler)
-static mDNSBool terminate = 0;
-static mDNSBool dumptable = 0;
-
-//
-// Logging Routines
-// Log messages are delivered to syslog unless -f option specified
-//
-
-// common message logging subroutine
-mDNSlocal void PrintLog(const char *buffer)
- {
- if (foreground)
- {
- fprintf(stderr,"%s\n", buffer);
- fflush(stderr);
- }
- else
- {
- openlog("dnsextd", LOG_CONS | LOG_PERROR, LOG_DAEMON);
- syslog(LOG_ERR, "%s", buffer);
- closelog();
- }
- }
-
-// Verbose Logging (conditional on -v option)
-mDNSlocal void VLog(const char *format, ...)
- {
- char buffer[512];
- va_list ptr;
-
- if (!verbose) return;
- va_start(ptr,format);
- buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
- va_end(ptr);
- PrintLog(buffer);
- }
-
-// Unconditional Logging
-mDNSlocal void Log(const char *format, ...)
- {
- char buffer[512];
- va_list ptr;
-
- va_start(ptr,format);
- buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
- va_end(ptr);
- PrintLog(buffer);
- }
-
-// Error Logging
-// prints message "dnsextd <function>: <operation> - <error message>"
-// must be compiled w/ -D_REENTRANT for thread-safe errno usage
-mDNSlocal void LogErr(const char *fn, const char *operation)
- {
- char buf[512];
- snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, strerror(errno));
- PrintLog(buf);
- }
-
-//
-// Networking Utility Routines
-//
-
-// Convert DNS Message Header from Network to Host byte order
-mDNSlocal void HdrNToH(PktMsg *pkt)
- {
- // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
- mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
- pkt->msg.h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
- pkt->msg.h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
- pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
- pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
- }
-
-// Convert DNS Message Header from Host to Network byte order
-mDNSlocal void HdrHToN(PktMsg *pkt)
- {
- mDNSu16 numQuestions = pkt->msg.h.numQuestions;
- mDNSu16 numAnswers = pkt->msg.h.numAnswers;
- mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
- mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
- mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
-
- // Put all the integer values in IETF byte-order (MSB first, LSB second)
- *ptr++ = (mDNSu8)(numQuestions >> 8);
- *ptr++ = (mDNSu8)(numQuestions & 0xFF);
- *ptr++ = (mDNSu8)(numAnswers >> 8);
- *ptr++ = (mDNSu8)(numAnswers & 0xFF);
- *ptr++ = (mDNSu8)(numAuthorities >> 8);
- *ptr++ = (mDNSu8)(numAuthorities & 0xFF);
- *ptr++ = (mDNSu8)(numAdditionals >> 8);
- *ptr++ = (mDNSu8)(numAdditionals & 0xFF);
- }
-
-// create a socket connected to nameserver
-// caller terminates connection via close()
-mDNSlocal int ConnectToServer(DaemonInfo *d)
- {
- struct sockaddr_in servaddr;
- int sd;
-
- bzero(&servaddr, sizeof(servaddr));
- if (d->saddr.s_addr) servaddr.sin_addr = d->saddr;
- else inet_pton(AF_INET, LOOPBACK, &d->saddr); // use loopback if server not explicitly specified
- servaddr.sin_port = htons(NS_PORT);
- servaddr.sin_family = AF_INET;
-#ifndef NOT_HAVE_SA_LEN
- servaddr.sin_len = sizeof(servaddr);
-#endif
- sd = socket(AF_INET, SOCK_STREAM, 0);
- if (sd < 0) { LogErr("ConnectToServer", "socket"); return -1; }
- if (connect(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { LogErr("ConnectToServer", "connect"); return -1; }
- return sd;
- }
-
-// send an entire block of data over a connected socket, blocking if buffers are full
-mDNSlocal int MySend(int sd, const void *msg, int len)
- {
- int n, nsent = 0;
-
- while (nsent < len)
- {
- n = send(sd, (char *)msg + nsent, len - nsent, 0);
- if (n < 0) { LogErr("MySend", "send"); return -1; }
- nsent += n;
- }
- return 0;
- }
-
-// Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
-mDNSlocal int SendTCPMsg(int sd, PktMsg *pkt)
- {
- // send the lenth, in network byte order
- mDNSu16 len = htons((mDNSu16)pkt->len);
- if (MySend(sd, &len, sizeof(len)) < 0) return -1;
-
- // send the message
- return MySend(sd, &pkt->msg, pkt->len);
- }
-
-// Receive len bytes, waiting until we have all of them.
-// Returns number of bytes read (which should always be the number asked for).
-static int my_recv(const int sd, void *const buf, const int len)
- {
- // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
- // use an explicit while() loop instead.
- // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
- // arithmetic on "void *" pointers is compiler-dependent.
- int remaining = len;
- char *ptr = (char *)buf;
- while (remaining)
- {
- ssize_t num_read = recv(sd, ptr, remaining, 0);
- if ((num_read == 0) || (num_read < 0) || (num_read > remaining)) return -1;
- ptr += num_read;
- remaining -= num_read;
- }
- return(len);
- }
-
-// Return a DNS Message read off of a TCP socket, or NULL on failure
-// If storage is non-null, result is placed in that buffer. Otherwise,
-// returned value is allocated with Malloc, and contains sufficient extra
-// storage for a Lease OPT RR
-
-mDNSlocal PktMsg *ReadTCPMsg(int sd, PktMsg *storage)
- {
- int nread, allocsize;
- mDNSu16 msglen = 0;
- PktMsg *pkt = NULL;
- unsigned int srclen;
-
- nread = my_recv(sd, &msglen, sizeof(msglen));
- if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; }
- msglen = ntohs(msglen);
- if (nread != sizeof(msglen)) { Log("Could not read length field of message"); goto error; }
-
- if (storage)
- {
- if (msglen > sizeof(storage->msg)) { Log("ReadTCPMsg: provided buffer too small."); goto error; }
- pkt = storage;
- }
- else
- {
- // buffer extra space to add an OPT RR
- if (msglen > sizeof(DNSMessage)) allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
- else allocsize = sizeof(PktMsg);
- pkt = malloc(allocsize);
- if (!pkt) { LogErr("ReadTCPMsg", "malloc"); goto error; }
- bzero(pkt, sizeof(*pkt));
- }
-
- pkt->len = msglen;
- srclen = sizeof(pkt->src);
- if (getpeername(sd, (struct sockaddr *)&pkt->src, &srclen) ||
- srclen != sizeof(pkt->src)) { LogErr("ReadTCPMsg", "getpeername"); bzero(&pkt->src, sizeof(pkt->src)); }
- nread = my_recv(sd, &pkt->msg, msglen);
- if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; }
- if (nread != msglen) { Log("Could not read entire message"); goto error; }
- if (pkt->len < sizeof(DNSMessageHeader))
- { Log("ReadTCPMsg: Message too short (%d bytes)", pkt->len); goto error; }
- HdrNToH(pkt);
- return pkt;
- //!!!KRS convert to HBO here?
- error:
- if (pkt && pkt != storage) free(pkt);
- return NULL;
- }
-
-//
-// Dynamic Update Utility Routines
-//
-
-// Get the lease life of records in a dynamic update
-// returns -1 on error or if no lease present
-mDNSlocal mDNSs32 GetPktLease(PktMsg *pkt)
- {
- mDNSs32 lease = -1;
- const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
- LargeCacheRecord lcr;
- int i;
-
- HdrNToH(pkt);
- ptr = LocateAdditionals(&pkt->msg, end);
- if (ptr)
- for (i = 0; i < pkt->msg.h.numAdditionals; i++)
- {
- ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
- if (!ptr) { Log("Unable to read additional record"); break; }
- if (lcr.r.resrec.rrtype == kDNSType_OPT)
- {
- if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue;
- if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue;
- lease = (mDNSs32)lcr.r.resrec.rdata->u.opt.OptData.lease;
- break;
- }
- }
-
- HdrHToN(pkt);
- return lease;
- }
-
-// check if a request and server response complete a successful dynamic update
-mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
- {
- char buf[32];
- char *vlogmsg = NULL;
-
- // check messages
- if (!request || !reply) { vlogmsg = "NULL message"; goto failure; }
- if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; }
-
- // check request operation
- if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask))
- { vlogmsg = "Request opcode not an update"; goto failure; }
-
- // check result
- if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC)) { vlogmsg = "Reply contains non-zero rcode"; goto failure; }
- if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response))
- { vlogmsg = "Reply opcode not an update response"; goto failure; }
-
- VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32));
- return mDNStrue;
-
- failure:
- VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg);
- return mDNSfalse;
- }
-
-// Allocate an appropriately sized CacheRecord and copy data from original.
-// Name pointer in CacheRecord object is set to point to the name specified
-//
-mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name)
- {
- CacheRecord *cr;
- size_t size = sizeof(*cr);
- if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize;
- cr = malloc(size);
- if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
- memcpy(cr, orig, size);
- cr->resrec.rdata = (RData*)&cr->rdatastorage;
- cr->resrec.name = name;
-
- return cr;
- }
-
-
-//
-// Lease Hashtable Utility Routines
-//
-
-// double hash table size
-// caller must lock table prior to invocation
-mDNSlocal void RehashTable(DaemonInfo *d)
- {
- RRTableElem *ptr, *tmp, **new;
- int i, bucket, newnbuckets = d->nbuckets * 2;
-
- VLog("Rehashing lease table (new size %d buckets)", newnbuckets);
- new = malloc(sizeof(RRTableElem *) * newnbuckets);
- if (!new) { LogErr("RehashTable", "malloc"); return; }
- bzero(new, newnbuckets * sizeof(RRTableElem *));
-
- for (i = 0; i < d->nbuckets; i++)
- {
- ptr = d->table[i];
- while (ptr)
- {
- bucket = ptr->rr.resrec.namehash % newnbuckets;
- tmp = ptr;
- ptr = ptr->next;
- tmp->next = new[bucket];
- new[bucket] = tmp;
- }
- }
- d->nbuckets = newnbuckets;
- free(d->table);
- d->table = new;
- }
-
-// print entire contents of hashtable, invoked via SIGINFO
-mDNSlocal void PrintLeaseTable(DaemonInfo *d)
- {
- int i;
- RRTableElem *ptr;
- char rrbuf[80], addrbuf[16];
- struct timeval now;
- int hr, min, sec;
-
- if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; }
- if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
-
- Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems);
- for (i = 0; i < d->nbuckets; i++)
- {
- for (ptr = d->table[i]; ptr; ptr = ptr->next)
- {
- hr = ((ptr->expire - now.tv_sec) / 60) / 60;
- min = ((ptr->expire - now.tv_sec) / 60) % 60;
- sec = (ptr->expire - now.tv_sec) % 60;
- Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET, &ptr->cli.sin_addr, addrbuf, 16), hr, min, sec,
- GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf));
- }
- }
- pthread_mutex_unlock(&d->tablelock);
- }
-
-//
-// Startup SRV Registration Routines
-// Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
-// the daemon accepts requests
-//
-
-// delete all RRS of a given name/type
-mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit, ResourceRecord *rr)
- {
- ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
- if (!ptr || ptr + 10 >= limit) return NULL; // out of space
- ptr[0] = (mDNSu8)(rr->rrtype >> 8);
- ptr[1] = (mDNSu8)(rr->rrtype & 0xFF);
- ptr[2] = (mDNSu8)((mDNSu16)kDNSQClass_ANY >> 8);
- ptr[3] = (mDNSu8)((mDNSu16)kDNSQClass_ANY & 0xFF);
- bzero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata
- msg->h.mDNS_numUpdates++;
- return ptr + 10;
- }
-
-mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSBool registration)
- {
- AuthRecord rr;
- char hostname[1024], buf[80];
- mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage);
-
- mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, NULL, NULL);
- rr.resrec.rrclass = kDNSClass_IN;
- rr.resrec.rdata->u.srv.priority = 0;
- rr.resrec.rdata->u.srv.weight = 0;
- rr.resrec.rdata->u.srv.port.NotAnInteger = d->port.NotAnInteger;
- if (!gethostname(hostname, 1024) < 0 || MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
- rr.resrec.rdata->u.srv.target.c[0] = '\0';
-
- MakeDomainNameFromDNSNameString(rr.resrec.name, regtype);
- AppendDomainName(rr.resrec.name, &d->zone);
- VLog("%s %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
- GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
- if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
- else ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec);
- return ptr;
- }
-
-
-// perform dynamic update.
-// specify deletion by passing false for the register parameter, otherwise register the records.
-mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
- {
- int sd = -1;
- mDNSOpaque16 id;
- PktMsg pkt;
- mDNSu8 *ptr = pkt.msg.data;
- mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
- mDNSu16 nAdditHBO; // num additionas, in host byte order, required by message digest routine
- PktMsg *reply = NULL;
-
- int result = -1;
-
- // Initialize message
- id.NotAnInteger = 0;
- InitializeDNSMessage(&pkt.msg.h, id, UpdateReqFlags);
- pkt.src.sin_addr.s_addr = htonl(INADDR_ANY); // address field set solely for verbose logging in subroutines
- pkt.src.sin_family = AF_INET;
-
- // format message body
- ptr = putZone(&pkt.msg, ptr, end, &d->zone, mDNSOpaque16fromIntVal(kDNSClass_IN));
- if (!ptr) goto end;
-
- ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-update._udp.", registration); if (!ptr) goto end;
- ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-update._tcp.", registration); if (!ptr) goto end;
- ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-llq._udp.", registration); if (!ptr) goto end;
-
- nAdditHBO = pkt.msg.h.numAdditionals;
- HdrHToN(&pkt);
- if (d->AuthInfo)
- {
- ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, &nAdditHBO, d->AuthInfo);
- if (!ptr) goto end;
- }
- pkt.len = ptr - (mDNSu8 *)&pkt.msg;
-
- // send message, receive reply
- sd = ConnectToServer(d);
- if (sd < 0) { Log("UpdateSRV: ConnectToServer failed"); goto end; }
- if (SendTCPMsg(sd, &pkt)) { Log("UpdateSRV: SendTCPMsg failed"); }
- reply = ReadTCPMsg(sd, NULL);
- if (!SuccessfulUpdateTransaction(&pkt, reply))
- Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC);
- else result = 0;
-
- end:
- if (!ptr) { Log("UpdateSRV: Error constructing lease expiration update"); }
- if (sd >= 0) close(sd);
- if (reply) free(reply);
- return result;
- }
-
-// wrapper routines/macros
-#define ClearUpdateSRV(d) UpdateSRV(d, 0)
-
-// clear any existing records prior to registration
-mDNSlocal int SetUpdateSRV(DaemonInfo *d)
- {
- int err;
-
- err = ClearUpdateSRV(d); // clear any existing record
- if (!err) err = UpdateSRV(d, 1);
- return err;
- }
-
-//
-// Argument Parsing and Configuration
-//
-
-// read authentication information for a zone from command line argument
-// global optind corresponds to keyname argument on entry
-mDNSlocal int ReadAuthKey(int argc, char *argv[], DaemonInfo *d)
- {
- uDNS_AuthInfo *auth = NULL;
- unsigned char keybuf[512];
- mDNSs32 keylen;
-
- auth = malloc(sizeof(*auth));
- if (!auth) { perror("ReadAuthKey, malloc"); goto error; }
- auth->next = NULL;
- if (argc < optind + 1) return -1; // keyname + secret
- if (!MakeDomainNameFromDNSNameString(&auth->keyname, optarg))
- { fprintf(stderr, "Bad key name %s", optarg); goto error; }
- keylen = DNSDigest_Base64ToBin(argv[optind++], keybuf, 512);
- if (keylen < 0)
- { fprintf(stderr, "Bad shared secret %s (must be base-64 encoded string)", argv[optind-1]); goto error; }
- DNSDigest_ConstructHMACKey(auth, keybuf, (mDNSu32)keylen);
- d->AuthInfo = auth;
- return 0;
-
- error:
- if (auth) free(auth);
- return -1;
- }
-
-mDNSlocal int SetPort(DaemonInfo *d, char *PortAsString)
- {
- long l;
-
- l = strtol(PortAsString, NULL, 10); // convert string to long
- if ((!l && errno == EINVAL) || l > 65535) return -1; // error check conversion
- d->port.NotAnInteger = htons((mDNSu16)l); // set to network byte order
- return 0;
- }
-
-mDNSlocal void PrintUsage(void)
- {
- fprintf(stderr, "Usage: dnsextd -z <zone> [-vf] [ -s server ] [-k keyname secret] ...\n"
- "Use \"dnsextd -h\" for help\n");
- }
-
-mDNSlocal void PrintHelp(void)
- {
- fprintf(stderr, "\n\n");
- PrintUsage();
-
- fprintf(stderr,
- "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
- "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
- "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
- "Discovery, Update Leases, and Long Lived Queries.)\n\n"
-
- "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
- "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
- "primary master server for this zone.\n\n"
-
- "The options are as follows:\n\n"
-
- "-f Run daemon in foreground.\n\n"
-
- "-h Print help.\n\n"
-
- "-k Specify TSIG authentication key for dynamic updates from daemon to name server.\n"
- " -k option is followed by the name of the key, and the shared secret as a base-64\n"
- " encoded string. This key/secret are used by the daemon to delete resource records\n"
- " from the server when leases expire. Clients are responsible for signing their\n"
- " update requests.\n\n"
-
- "-s Specify address (IPv4 address in dotted-decimal notation) of the Primary Master\n"
- " name server. Defaults to loopback (127.0.0.1), i.e. daemon and name server\n"
- " running on the same machine.\n\n"
-
- "-v Verbose output.\n\n"
- );
- }
-
-// Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
-// returns 0 (success) if program is to continue execution
-// output control arguments (-f, -v) do not affect this routine
-mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
- {
- int opt;
-
- if (argc < 2) goto arg_error;
-
- d->port.NotAnInteger = htons(DAEMON_PORT); // default, may be overriden by command option
- while ((opt = getopt(argc, argv, "z:p:hfvs:k:")) != -1)
- {
- switch(opt)
- {
- case 'p': if (SetPort(d, optarg) < 0) goto arg_error;
- break;
-
- case 'h': PrintHelp(); return -1;
- case 'f': foreground = 1; break;
- case 'v': verbose = 1; break;
- case 's': if (!inet_pton(AF_INET, optarg, &d->saddr)) goto arg_error;
- break;
- case 'k': if (ReadAuthKey(argc, argv, d) < 0) goto arg_error;
- break;
- case 'z': if (!MakeDomainNameFromDNSNameString(&d->zone, optarg))
- {
- fprintf(stderr, "Bad zone %s", optarg);
- goto arg_error;
- }
- break;
- default: goto arg_error;
- }
- }
-
- if (!d->zone.c[0]) goto arg_error; // zone is the only required argument
- if (d->AuthInfo) AssignDomainName(&d->AuthInfo->zone, &d->zone); // if we have a shared secret, use it for the entire zone
- return 0;
-
- arg_error:
- PrintUsage();
- return -1;
- }
-
-
-//
-// Initialization Routines
-//
-
-// Allocate memory, initialize locks and bookkeeping variables
-mDNSlocal int InitLeaseTable(DaemonInfo *d)
- {
- if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
- d->nbuckets = LEASETABLE_INIT_NBUCKETS;
- d->nelems = 0;
- d->table = malloc(sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
- if (!d->table) { LogErr("InitLeaseTable", "malloc"); return -1; }
- bzero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
- return 0;
- }
-mDNSlocal int SetupSockets(DaemonInfo *daemon)
- {
- struct sockaddr_in daddr;
- int sockpair[2];
-
- // set up sockets on which we receive requests
- bzero(&daddr, sizeof(daddr));
- daddr.sin_family = AF_INET;
- daddr.sin_addr.s_addr = htonl(INADDR_ANY);
-
- if (daemon->port.NotAnInteger) daddr.sin_port = daemon->port.NotAnInteger;
- else daddr.sin_port = htons(DAEMON_PORT);
-
- daemon->tcpsd = socket(AF_INET, SOCK_STREAM, 0);
- if (!daemon->tcpsd) { LogErr("SetupSockets", "socket"); return -1; }
- if (bind(daemon->tcpsd, (struct sockaddr *)&daddr, sizeof(daddr)) < 0) { LogErr("SetupSockets", "bind"); return -1; }
- if (listen(daemon->tcpsd, LISTENQ) < 0) { LogErr("SetupSockets", "listen"); return -1; }
-
- daemon->udpsd = socket(AF_INET, SOCK_DGRAM, 0);
- if (!daemon->udpsd) { LogErr("SetupSockets", "socket"); return -1; }
- if (bind(daemon->udpsd, (struct sockaddr *)&daddr, sizeof(daddr)) < 0) { LogErr("SetupSockets", "bind"); return -1; }
-
- // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
- if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockpair) < 0) { LogErr("SetupSockets", "socketpair"); return -1; }
- daemon->LLQEventListenSock = sockpair[0];
- daemon->LLQServPollSock = sockpair[1];
- return 0;
- }
-
-//
-// periodic table updates
-//
-
-// Delete a resource record from the nameserver via a dynamic update
-mDNSlocal void DeleteRecord(DaemonInfo *d, CacheRecord *rr, domainname *zone)
- {
- int sd = -1;
- mDNSOpaque16 id;
- PktMsg pkt;
- mDNSu8 *ptr = pkt.msg.data;
- mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
- mDNSu16 nAdditHBO; // num additionas, in host byte order, required by message digest routine
- char buf[80];
- PktMsg *reply = NULL;
-
- VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf));
- sd = ConnectToServer(d);
- if (sd < 0) { Log("DeleteRecord: ConnectToServer failed"); goto end; }
-
- id.NotAnInteger = 0;
- InitializeDNSMessage(&pkt.msg.h, id, UpdateReqFlags);
-
- ptr = putZone(&pkt.msg, ptr, end, zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
- if (!ptr) goto end;
- ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec);
- if (!ptr) goto end;
-
- nAdditHBO = pkt.msg.h.numAdditionals;
- HdrHToN(&pkt);
-
- if (d->AuthInfo)
- {
- ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, &nAdditHBO, d->AuthInfo);
- if (!ptr) goto end;
- }
-
- pkt.len = ptr - (mDNSu8 *)&pkt.msg;
- pkt.src.sin_addr.s_addr = htonl(INADDR_ANY); // address field set solely for verbose logging in subroutines
- pkt.src.sin_family = AF_INET;
- if (SendTCPMsg(sd, &pkt)) { Log("DeleteRecord: SendTCPMsg failed"); }
- reply = ReadTCPMsg(sd, NULL);
- if (!SuccessfulUpdateTransaction(&pkt, reply))
- Log("Expiration update failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC);
-
- end:
- if (!ptr) { Log("DeleteRecord: Error constructing lease expiration update"); }
- if (sd >= 0) close(sd);
- if (reply) free(reply);
- }
-
-// iterate over table, deleting expired records
-mDNSlocal void DeleteExpiredRecords(DaemonInfo *d)
- {
- int i;
- RRTableElem *ptr, *prev, *fptr;
- struct timeval now;
-
- if (gettimeofday(&now, NULL)) { LogErr("DeleteExpiredRecords ", "gettimeofday"); return; }
- if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteExpiredRecords", "pthread_mutex_lock"); return; }
- for (i = 0; i < d->nbuckets; i++)
- {
- ptr = d->table[i];
- prev = NULL;
- while (ptr)
- {
- if (ptr->expire - now.tv_sec < 0)
- {
- // delete record from server
- DeleteRecord(d, &ptr->rr, &ptr->zone);
- if (prev) prev->next = ptr->next;
- else d->table[i] = ptr->next;
- fptr = ptr;
- ptr = ptr->next;
- free(fptr);
- d->nelems--;
- }
- else
- {
- prev = ptr;
- ptr = ptr->next;
- }
- }
- }
- pthread_mutex_unlock(&d->tablelock);
- }
-
-//
-// main update request handling
-//
-
-// Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
-mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
- {
- RRTableElem **rptr, *tmp;
- int i, allocsize, bucket;
- LargeCacheRecord lcr;
- ResourceRecord *rr = &lcr.r.resrec;
- const mDNSu8 *ptr, *end;
- struct timeval time;
- DNSQuestion zone;
- char buf[80];
-
- if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
- HdrNToH(pkt);
- ptr = pkt->msg.data;
- end = (mDNSu8 *)&pkt->msg + pkt->len;
- ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone);
- if (!ptr) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup; }
- ptr = LocateAuthorities(&pkt->msg, end);
- if (!ptr) { Log("UpdateLeaseTable: Format error"); goto cleanup; }
-
- for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++)
- {
- mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse;
-
- ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ptr) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup; }
- bucket = rr->namehash % d->nbuckets;
- rptr = &d->table[bucket];
-
- // handle deletions
- if (rr->rrtype == kDNSQType_ANY && !rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
- DeleteAllRRSets = mDNStrue; // delete all rrsets for a name
- else if (!rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
- DeleteOneRRSet = mDNStrue;
- else if (!rr->rroriginalttl && rr->rrclass == kDNSClass_NONE)
- DeleteOneRR = mDNStrue;
-
- if (DeleteAllRRSets || DeleteOneRRSet || DeleteOneRR)
- {
- while (*rptr)
- {
- if (SameDomainName((*rptr)->rr.resrec.name, rr->name) &&
- (DeleteAllRRSets ||
- (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) ||
- (DeleteOneRR && SameResourceRecord(&(*rptr)->rr.resrec, rr))))
- {
- tmp = *rptr;
- VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf));
- *rptr = (*rptr)->next;
- free(tmp);
- d->nelems--;
- }
- else rptr = &(*rptr)->next;
- }
- }
- else if (lease > 0)
- {
- // see if add or refresh
- while (*rptr && !SameResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
- if (*rptr)
- {
- // refresh
- if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
- (*rptr)->expire = time.tv_sec + (unsigned)lease;
- VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
- }
- else
- {
- // New record - add to table
- if (d->nelems > d->nbuckets)
- {
- RehashTable(d);
- bucket = rr->namehash % d->nbuckets;
- rptr = &d->table[bucket];
- }
- if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
- allocsize = sizeof(RRTableElem);
- if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize);
- tmp = malloc(allocsize);
- if (!tmp) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; }
- memcpy(&tmp->rr, &lcr.r, sizeof(CacheRecord) + rr->rdlength - InlineCacheRDSize);
- tmp->rr.resrec.rdata = (RData *)&tmp->rr.rdatastorage;
- AssignDomainName(&tmp->name, rr->name);
- tmp->rr.resrec.name = &tmp->name;
- tmp->expire = time.tv_sec + (unsigned)lease;
- tmp->cli.sin_addr = pkt->src.sin_addr;
- AssignDomainName(&tmp->zone, &zone.qname);
- tmp->next = d->table[bucket];
- d->table[bucket] = tmp;
- d->nelems++;
- VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
- }
- }
- }
-
- cleanup:
- pthread_mutex_unlock(&d->tablelock);
- HdrHToN(pkt);
- }
-
-// Given a successful reply from a server, create a new reply that contains lease information
-// Replies are currently not signed !!!KRS change this
-mDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease)
- {
- PktMsg *reply;
- mDNSu8 *ptr, *end;
- mDNSOpaque16 flags;
-
- (void)d; //unused
- reply = malloc(sizeof(*reply));
- if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; }
- flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
- flags.b[1] = 0;
-
- InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags);
- reply->src.sin_addr.s_addr = htonl(INADDR_ANY); // unused except for log messages
- reply->src.sin_family = AF_INET;
- ptr = reply->msg.data;
- end = (mDNSu8 *)&reply->msg + sizeof(DNSMessage);
- ptr = putUpdateLease(&reply->msg, ptr, lease);
- if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; }
- reply->len = ptr - (mDNSu8 *)&reply->msg;
- return reply;
- }
-
-// pkt is thread-local, not requiring locking
-mDNSlocal PktMsg *HandleRequest(PktMsg *pkt, DaemonInfo *d)
- {
- int sd = -1;
- PktMsg *reply = NULL, *LeaseReply;
- mDNSs32 lease;
- char buf[32];
-
- // send msg to server, read reply
- sd = ConnectToServer(d);
- if (sd < 0)
- { Log("Discarding request from %s due to connection errors", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; }
- if (SendTCPMsg(sd, pkt) < 0)
- { Log("Couldn't relay message from %s to server. Discarding.", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; }
- reply = ReadTCPMsg(sd, NULL);
-
- // process reply
- if (!SuccessfulUpdateTransaction(pkt, reply))
- { VLog("Message from %s not a successful update.", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; }
- lease = GetPktLease(pkt);
- UpdateLeaseTable(pkt, d, lease);
- if (lease > 0)
- {
- LeaseReply = FormatLeaseReply(d, reply, lease);
- if (!LeaseReply) Log("HandleRequest - unable to format lease reply");
- free(reply);
- reply = LeaseReply;
- }
- cleanup:
- if (sd >= 0) close(sd);
- return reply;
- }
-
-
-//
-// LLQ Support Routines
-//
-
-// Set fields of an LLQ Opt Resource Record
-mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, mDNSu8 *id, mDNSs32 lease)
- {
- bzero(opt, sizeof(*opt));
- mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
- opt->resrec.rdlength = LLQ_OPT_RDLEN;
- opt->resrec.rdestimate = LLQ_OPT_RDLEN;
- opt->resrec.rdata->u.opt.opt = kDNSOpt_LLQ;
- opt->resrec.rdata->u.opt.optlen = sizeof(LLQOptData);
- opt->resrec.rdata->u.opt.OptData.llq.vers = kLLQ_Vers;
- opt->resrec.rdata->u.opt.OptData.llq.llqOp = opcode;
- opt->resrec.rdata->u.opt.OptData.llq.err = LLQErr_NoError;
- memcpy(opt->resrec.rdata->u.opt.OptData.llq.id, id, 8);
- opt->resrec.rdata->u.opt.OptData.llq.lease = lease;
- }
-
-// Calculate effective remaining lease of an LLQ
-mDNSlocal mDNSu32 LLQLease(LLQEntry *e)
- {
- struct timeval t;
-
- gettimeofday(&t, NULL);
- if (e->expire < t.tv_sec) return 0;
- else return e->expire - t.tv_sec;
- }
-
-mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
- {
- int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
- LLQEntry **ptr = &d->LLQTable[bucket];
- AnswerListElem *a = e->AnswerList;
- char addr[32];
-
- inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
- VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
-
- // free shared answer structure if ref count drops to zero
- if (a && !(--a->refcount))
- {
- CacheRecord *cr = a->KnownAnswers, *tmp;
- AnswerListElem **tbl = &d->AnswerTable[bucket];
-
- while (cr)
- {
- tmp = cr;
- cr = cr->next;
- free(tmp);
- }
-
- while (*tbl && *tbl != a) tbl = &(*tbl)->next;
- if (*tbl) { *tbl = (*tbl)->next; free(a); }
- else Log("Error: DeleteLLQ - AnswerList not found in table");
- }
-
- // remove LLQ from table, free memory
- while(*ptr && *ptr != e) ptr = &(*ptr)->next;
- if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
- *ptr = (*ptr)->next;
- free(e);
- }
-
-mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst)
- {
- char addr[32];
- int err = -1;
-
- HdrHToN(pkt);
- if (sendto(d->udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
- {
- LogErr("DaemonInfo", "sendto");
- Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
- }
- else err = 0;
- HdrNToH(pkt);
- return err;
- }
-
-// if non-negative, sd is a TCP socket connected to the nameserver
-// otherwise, this routine creates and closes its own socket
-mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e, int sd)
- {
- PktMsg q;
- int i;
- const mDNSu8 *ansptr;
- mDNSu8 *end = q.msg.data;
- mDNSOpaque16 id, flags = QueryFlags;
- PktMsg *reply = NULL;
- LargeCacheRecord lcr;
- CacheRecord *AnswerList = NULL;
- mDNSu8 rcode;
- mDNSBool CloseSDOnExit = sd < 0;
-
- VLog("Querying server for %##s type %d", e->name.c, e->type);
-
- flags.b[0] |= kDNSFlag0_RD; // recursion desired
- id.NotAnInteger = 0;
- InitializeDNSMessage(&q.msg.h, id, flags);
-
- end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN);
- if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
- q.len = (int)(end - (mDNSu8 *)&q.msg);
-
- if (sd < 0) sd = ConnectToServer(d);
- if (sd < 0) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
- if (SendTCPMsg(sd, &q)) { Log("AnswerQuestion: SendTCPMsg failed"); close(sd); goto end; }
- reply = ReadTCPMsg(sd, NULL);
-
- if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
- { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
- rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC);
- if (rcode && rcode != kDNSFlag1_RC_NXDomain) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e->name.c, e->type, rcode); goto end; }
-
- end = (mDNSu8 *)&reply->msg + reply->len;
- ansptr = LocateAnswers(&reply->msg, end);
- if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
-
- for (i = 0; i < reply->msg.h.numAnswers; i++)
- {
- ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
- if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
- {
- Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
- lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
- }
- else
- {
- CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
- if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
- cr->next = AnswerList;
- AnswerList = cr;
- }
- }
-
- end:
- if (sd > -1 && CloseSDOnExit) close(sd);
- if (reply) free(reply);
- return AnswerList;
- }
-
-// Routine sets EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
-mDNSlocal void UpdateAnswerList(DaemonInfo *d, AnswerListElem *a, int sd)
- {
- CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer"
-
- // get up to date answers
- NewAnswers = AnswerQuestion(d, a, sd);
-
- // first pass - mark all answers for deletion
- for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
- (*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete
-
- // second pass - mark answers pre-existent
- for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
- {
- for (na = &NewAnswers; *na; na = &(*na)->next)
- {
- if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec))
- { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
- }
- }
-
- // third pass - add new records to Event list
- na = &NewAnswers;
- while (*na)
- {
- for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
- if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
- if (!*ka)
- {
- // answer is not in list - splice from NewAnswers list, add to Event list
- cr = *na;
- *na = (*na)->next; // splice from list
- cr->next = a->EventList; // add spliced record to event list
- a->EventList = cr;
- cr->resrec.rroriginalttl = 1; // 1 means add
- }
- else na = &(*na)->next;
- }
-
- // move all the removes from the answer list to the event list
- ka = &a->KnownAnswers;
- while (*ka)
- {
- if ((*ka)->resrec.rroriginalttl == (unsigned)-1)
- {
- cr = *ka;
- *ka = (*ka)->next;
- cr->next = a->EventList;
- a->EventList = cr;
- }
- else ka = &(*ka)->next;
- }
-
- // lastly, free the remaining records (known answers) in NewAnswers list
- while (NewAnswers)
- {
- cr = NewAnswers;
- NewAnswers = NewAnswers->next;
- free(cr);
- }
- }
-
-mDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e)
- {
- PktMsg response;
- CacheRecord *cr;
- mDNSu8 *end = (mDNSu8 *)&response.msg.data;
- mDNSOpaque16 msgID;
- char rrbuf[80], addrbuf[32];
- AuthRecord opt;
-
- msgID.NotAnInteger = random();
- if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
- InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
- end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
- if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
-
- // put adds/removes in packet
- for (cr = e->AnswerList->EventList; cr; cr = cr->next)
- {
- if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf);
- VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove": "Add", rrbuf);
- end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl);
- if (!end) { Log("Error: SendEvents - UpdateAnswerList returned NULL"); return; }
- }
-
- FormatLLQOpt(&opt, kLLQOp_Event, e->id, LLQLease(e));
- end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
- if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
-
- response.len = (int)(end - (mDNSu8 *)&response.msg);
- if (SendLLQ(d, &response, e->cli) < 0) LogMsg("Error: SendEvents - SendLLQ");
- }
-
-mDNSlocal void PrintLLQTable(DaemonInfo *d)
- {
- LLQEntry *e;
- char addr[32];
- int i;
-
- Log("Printing LLQ table contents");
-
- for (i = 0; i < LLQ_TABLESIZE; i++)
- {
- e = d->LLQTable[i];
- while(e)
- {
- inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
- Log("LLQ from %##s type %d lease %d (%d remaining)",
- addr, e->qname.c, e->qtype, e->lease, LLQLease(e));
- e = e->next;
- }
- }
- }
-
-// Send events to clients as a result of a change in the zone
-mDNSlocal void GenLLQEvents(DaemonInfo *d)
- {
- LLQEntry **e;
- int i, sd;
- struct timeval t;
-
- VLog("Generating LLQ Events");
-
- gettimeofday(&t, NULL);
- sd = ConnectToServer(d);
- if (sd < 0) { Log("GenLLQEvents: ConnectToServer failed"); return; }
-
- // get all answers up to date
- for (i = 0; i < LLQ_TABLESIZE; i++)
- {
- AnswerListElem *a = d->AnswerTable[i];
- while(a)
- {
- UpdateAnswerList(d, a, sd);
- a = a->next;
- }
- }
-
- // for each established LLQ, send events
- for (i = 0; i < LLQ_TABLESIZE; i++)
- {
- e = &d->LLQTable[i];
- while(*e)
- {
- if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e);
- else
- {
- if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e);
- e = &(*e)->next;
- }
- }
- }
-
- // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
- for (i = 0; i < LLQ_TABLESIZE; i++)
- {
- AnswerListElem *a = d->AnswerTable[i];
- while(a)
- {
- if (a->EventList)
- {
- CacheRecord *cr = a->EventList, *tmp;
- while (cr)
- {
- tmp = cr;
- cr = cr->next;
- if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp);
- else
- {
- tmp->next = a->KnownAnswers;
- a->KnownAnswers = tmp;
- tmp->resrec.rroriginalttl = 0;
- }
- }
- a->EventList = NULL;
- }
- a = a->next;
- }
- }
-
- close(sd);
- }
-
-// Monitor zone for changes that may produce LLQ events
-mDNSlocal void *LLQEventMonitor(void *DInfoPtr)
- {
- DaemonInfo *d = DInfoPtr;
- PktMsg q;
- mDNSu8 *end = q.msg.data;
- const mDNSu8 *ptr;
- mDNSOpaque16 id, flags = QueryFlags;
- PktMsg reply;
- mDNSs32 serial = 0;
- mDNSBool SerialInitialized = mDNSfalse;
- int sd;
- LargeCacheRecord lcr;
- ResourceRecord *rr = &lcr.r.resrec;
- int i, sleeptime = 0;
- domainname zone;
- char pingmsg[4];
-
- // create question
- id.NotAnInteger = 0;
- InitializeDNSMessage(&q.msg.h, id, flags);
- AssignDomainName(&zone, &d->zone);
- end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &zone, kDNSType_SOA, kDNSClass_IN);
- if (!end) { Log("Error: LLQEventMonitor - putQuestion returned NULL"); return NULL; }
- q.len = (int)(end - (mDNSu8 *)&q.msg);
-
- sd = ConnectToServer(d);
- if (sd < 0) { Log("LLQEventMonitor: ConnectToServer failed"); return NULL; }
-
- while(1)
- {
- usleep(sleeptime);
- sleeptime = LLQ_MONITOR_ERR_INTERVAL; // if we bail on error below, rate limit retry
-
- // send message, receive response
- if (SendTCPMsg(sd, &q)) { Log("LLQEventMonitor: SendTCPMsg failed"); continue; }
- if (!ReadTCPMsg(sd, &reply)) { Log("LLQEventMonitor: ReadTCPMsg failed"); continue; }
- end = (mDNSu8 *)&reply.msg + reply.len;
- if (reply.msg.h.flags.b[1] & kDNSFlag1_RC) { Log("LLQEventMonitor - received non-zero rcode"); continue; }
-
- // find answer
- ptr = LocateAnswers(&reply.msg, end);
- if (!ptr) { Log("Error: LLQEventMonitor - LocateAnswers returned NULL"); continue; }
- for (i = 0; i < reply.msg.h.numAnswers; i++)
- {
- ptr = GetLargeResourceRecord(NULL, &reply.msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
- if (!ptr) { Log("Error: LLQEventMonitor - GetLargeResourceRecord returned NULL"); continue; }
- if (rr->rrtype != kDNSType_SOA || rr->rrclass != kDNSClass_IN || !SameDomainName(rr->name, &zone)) continue;
- if (!SerialInitialized)
- {
- // first time through loop
- SerialInitialized = mDNStrue;
- serial = rr->rdata->u.soa.serial;
- sleeptime = LLQ_MONITOR_INTERVAL;
- break;
- }
- else if (rr->rdata->u.soa.serial != serial)
- {
- // update serial, wake main thread
- serial = rr->rdata->u.soa.serial;
- VLog("LLQEventMonitor: zone changed. Signaling main thread.");
- if (send(d->LLQServPollSock, pingmsg, sizeof(pingmsg), 0) != sizeof(pingmsg))
- { LogErr("LLQEventMonitor", "send"); break; }
- }
- sleeptime = LLQ_MONITOR_INTERVAL;
- break;
- }
- if (!ptr) Log("LLQEventMonitor: response to query did not contain SOA");
- }
- }
-
-mDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e)
- {
- int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
- AnswerListElem *a = d->AnswerTable[bucket];
- while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next;
- if (!a)
- {
- a = malloc(sizeof(*a));
- if (!a) { LogErr("SetAnswerList", "malloc"); return; }
- AssignDomainName(&a->name, &e->qname);
- a->type = e->qtype;
- a->refcount = 0;
- a->KnownAnswers = NULL;
- a->EventList = NULL;
- a->next = d->AnswerTable[bucket];
- d->AnswerTable[bucket] = a;
-
- // to get initial answer list, call UpdateAnswerList and move cache records from EventList to KnownAnswers
- UpdateAnswerList(d, a, -1);
- a->KnownAnswers = a->EventList;
- a->EventList = NULL;
- }
-
- e->AnswerList = a;
- a->refcount ++;
- }
-
- // Allocate LLQ entry, insert into table
-mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease)
- {
- char addr[32];
- struct timeval t;
- int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
- LLQEntry *e;
-
- e = malloc(sizeof(*e));
- if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
-
- inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
- VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
-
- // initialize structure
- e->cli = cli;
- AssignDomainName(&e->qname, qname);
- e->qtype = qtype;
- memset(e->id, 0, 8);
- e->state = RequestReceived;
- e->AnswerList = NULL;
-
- if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
- else if (lease > LLQ_MAX_LEASE) lease = LLQ_MIN_LEASE;
- gettimeofday(&t, NULL);
- e->expire = t.tv_sec + (int)lease;
- e->lease = lease;
-
- // add to table
- e->next = d->LLQTable[bucket];
- d->LLQTable[bucket] = e;
-
- return e;
- }
-
-// Handle a refresh request from client
-mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
- {
- AuthRecord opt;
- PktMsg ack;
- mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
- char addr[32];
-
- inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
- VLog("%s LLQ for %##s from %s", llq->lease ? "Refreshing" : "Deleting", e->qname.c, addr);
-
- if (llq->lease)
- {
- if (llq->lease < LLQ_MIN_LEASE) llq->lease = LLQ_MIN_LEASE;
- else if (llq->lease > LLQ_MAX_LEASE) llq->lease = LLQ_MIN_LEASE;
- }
-
- ack.src.sin_addr.s_addr = 0; // unused
- InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
- end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
- if (!end) { Log("Error: putQuestion"); return; }
-
- FormatLLQOpt(&opt, kLLQOp_Refresh, e->id, llq->lease ? LLQLease(e) : 0);
- end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
- if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
-
- ack.len = (int)(end - (mDNSu8 *)&ack.msg);
- if (SendLLQ(d, &ack, e->cli)) Log("Error: LLQRefresh");
-
- if (llq->lease) e->state = Established;
- else DeleteLLQ(d, e);
- }
-
-// Complete handshake with Ack an initial answers
-mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
- {
- char addr[32];
- CacheRecord *ptr;
- AuthRecord opt;
- PktMsg ack;
- mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
- char rrbuf[80], addrbuf[32];
-
- inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
-
- if (memcmp(llq->id, e->id, 8) ||
- llq->vers != kLLQ_Vers ||
- llq->llqOp != kLLQOp_Setup ||
- llq->err != LLQErr_NoError ||
- llq->lease > e->lease + LLQ_LEASE_FUDGE ||
- llq->lease < e->lease - LLQ_LEASE_FUDGE)
- { Log("Incorrect challenge response from %s", addr); return; }
-
- if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
- else VLog("Delivering LLQ ack + answers for %##s", e->qname.c);
-
- // format ack + answers
- ack.src.sin_addr.s_addr = 0; // unused
- InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
- end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
- if (!end) { Log("Error: putQuestion"); return; }
-
- if (e->state != Established) { SetAnswerList(d, e); e->state = Established; }
-
- if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
- for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next)
- {
- if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
- VLog("%s Intitial Answer - %s", addr, rrbuf);
- end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
- if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
- }
-
- FormatLLQOpt(&opt, kLLQOp_Setup, e->id, LLQLease(e));
- end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
- if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
-
- ack.len = (int)(end - (mDNSu8 *)&ack.msg);
- if (SendLLQ(d, &ack, e->cli)) Log("Error: LLQCompleteHandshake");
- }
-
-mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
- {
- struct timeval t;
- mDNSu32 randval;
- PktMsg challenge;
- mDNSu8 *end = challenge.msg.data;
- AuthRecord opt;
-
- if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
- else VLog("Sending LLQ setup challenge for %##s", e->qname.c);
-
- if (!ZERO_LLQID(llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
- if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
-
- if (ZERO_LLQID(e->id)) // don't regenerate random ID for retransmissions
- {
- // construct ID <time><random>
- gettimeofday(&t, NULL);
- randval = random();
- memcpy(e->id, &t.tv_sec, sizeof(t.tv_sec));
- memcpy(e->id + sizeof(t.tv_sec), &randval, sizeof(randval));
- }
-
- // format response (query + LLQ opt rr)
- challenge.src.sin_addr.s_addr = 0; // unused
- InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
- end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
- if (!end) { Log("Error: putQuestion"); return; }
- FormatLLQOpt(&opt, kLLQOp_Setup, e->id, LLQLease(e));
- end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
- if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
- challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
- if (SendLLQ(d, &challenge, e->cli)) { Log("Error: LLQSetupChallenge"); return; }
- e->state = ChallengeSent;
- }
-
-// Take action on an LLQ message from client. Entry must be initialized and in table
-mDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
- {
- switch(e->state)
- {
- case RequestReceived:
- LLQSetupChallenge(d, e, llq, msgID);
- return;
- case ChallengeSent:
- if (ZERO_LLQID(llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
- else LLQCompleteHandshake(d, e, llq, msgID);
- return;
- case Established:
- if (ZERO_LLQID(llq->id))
- {
- // client started over. reset state.
- LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->lease);
- if (!newe) return;
- DeleteLLQ(d, e);
- LLQSetupChallenge(d, newe, llq, msgID);
- return;
- }
- else if (llq->llqOp == kLLQOp_Setup)
- { LLQCompleteHandshake(d, e, llq, msgID); return; } // Ack lost
- else if (llq->llqOp == kLLQOp_Refresh)
- { LLQRefresh(d, e, llq, msgID); return; }
- else { Log("Unhandled message for established LLQ"); return; }
- }
- }
-
-mDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu8 *id)
- {
- int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
- LLQEntry *ptr = d->LLQTable[bucket];
-
- while(ptr)
- {
- if (((ptr->state == ChallengeSent && ZERO_LLQID(id)) || // zero-id due to packet loss OK in state ChallengeSent
- !memcmp(id, ptr->id, 8)) && // id match
- SAME_INADDR(cli, ptr->cli) && qtype == ptr->qtype && SameDomainName(&ptr->qname, qname)) // same source, type, qname
- return ptr;
- ptr = ptr->next;
- }
- return NULL;
- }
-
-mDNSlocal int RecvLLQ(DaemonInfo *d, PktMsg *pkt)
- {
- DNSQuestion q;
- LargeCacheRecord opt;
- int i, err = -1;
- char addr[32];
- const mDNSu8 *qptr = pkt->msg.data;
- const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
- const mDNSu8 *aptr = LocateAdditionals(&pkt->msg, end);
- LLQOptData *llq = NULL;
- LLQEntry *e = NULL;
-
- HdrNToH(pkt);
- inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
-
- VLog("Received LLQ msg from %s", addr);
- // sanity-check packet
- if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
- {
- Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);
- goto end;
- }
-
- // find the OPT RR - must be last in message
- for (i = 0; i < pkt->msg.h.numAdditionals; i++)
- {
- aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
- if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
- }
-
- // validate OPT
- if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an Opt RR", addr); goto end; }
- if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * LLQ_OPT_RDLEN) { Log("Malformatted LLQ from %s: Opt RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); }
-
- // dispatch each question
- for (i = 0; i < pkt->msg.h.numQuestions; i++)
- {
- qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
- if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; }
- llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt.OptData.llq + i; // point into OptData at index i
- if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
-
- e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, llq->id);
- if (!e)
- {
- // no entry - if zero ID, create new
- e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->lease);
- if (!e) goto end;
- }
- UpdateLLQ(d, e, llq, pkt->msg.h.id);
- }
- err = 0;
-
- end:
- HdrHToN(pkt);
- return err;
- }
-
-mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
- {
- const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
- LargeCacheRecord lcr;
- int i;
- mDNSBool result = mDNSfalse;
-
- HdrNToH(pkt);
- if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
-
- if (!pkt->msg.h.numAdditionals) goto end;
- ptr = LocateAdditionals(&pkt->msg, end);
- if (!ptr) goto end;
-
- // find last Additional
- for (i = 0; i < pkt->msg.h.numAdditionals; i++)
- {
- ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
- if (!ptr) { Log("Unable to read additional record"); goto end; }
- }
-
- if (lcr.r.resrec.rrtype == kDNSType_OPT &&
- lcr.r.resrec.rdlength >= LLQ_OPT_RDLEN &&
- lcr.r.resrec.rdata->u.opt.opt == kDNSOpt_LLQ)
- { result = mDNStrue; goto end; }
-
- end:
- HdrHToN(pkt);
- return result;
- }
-
-// !!!KRS implement properly
-mDNSlocal mDNSBool IsLLQAck(PktMsg *pkt)
- {
- if (pkt->msg.h.flags.NotAnInteger == ResponseFlags.NotAnInteger &&
- pkt->msg.h.numQuestions && !pkt->msg.h.numAnswers && !pkt->msg.h.numAuthorities) return mDNStrue;
- return mDNSfalse;
- }
-
-
-// request handler wrappers for TCP and UDP requests
-// (read message off socket, fork thread that invokes main processing routine and handles cleanup)
-mDNSlocal void *UDPUpdateRequestForkFn(void *vptr)
- {
- char buf[32];
- UDPRequestArgs *req = vptr;
- PktMsg *reply = NULL;
-
- VLog("Received UDP request: %d bytes from %s", req->pkt.len, inet_ntop(AF_INET, &req->pkt.src.sin_addr, buf, 32));
- //!!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server may give us a long answer that would require truncation for UDP delivery to client
- reply = HandleRequest(&req->pkt, req->d);
- if (reply)
- {
- if (sendto(req->d->udpsd, &reply->msg, reply->len, 0, (struct sockaddr *)&req->pkt.src, sizeof(req->pkt.src)) != (int)reply->len)
- LogErr("UDPUpdateRequestForkFn", "sendto");
- }
-
- if (reply) free(reply);
- free(req);
- pthread_exit(NULL);
- }
-
-//!!!KRS this needs to be changed to use non-blocking sockets
-mDNSlocal int RecvUDPRequest(int sd, DaemonInfo *d)
- {
- UDPRequestArgs *req;
- pthread_t tid;
- unsigned int clisize = sizeof(req->cliaddr);
-
- req = malloc(sizeof(UDPRequestArgs));
- if (!req) { LogErr("RecvUDPRequest", "malloc"); return -1; }
- bzero(req, sizeof(*req));
- req->d = d;
- req->pkt.len = recvfrom(sd, &req->pkt.msg, sizeof(req->pkt.msg), 0, (struct sockaddr *)&req->cliaddr, &clisize);
- if ((int)req->pkt.len < 0) { LogErr("RecvUDPRequest", "recvfrom"); free(req); return -1; }
- if (clisize != sizeof(req->cliaddr)) { Log("Client address of unknown size %d", clisize); free(req); return -1; }
- req->pkt.src = req->cliaddr;
-
- if (IsLLQRequest(&req->pkt))
- {
- // LLQ messages handled by main thread
- int err = RecvLLQ(d, &req->pkt);
- free(req);
- return err;
- }
-
- if (IsLLQAck(&req->pkt)) { free(req); return 0; } // !!!KRS need to do acks + retrans
-
- if (pthread_create(&tid, NULL, UDPUpdateRequestForkFn, req)) { LogErr("RecvUDPRequest", "pthread_create"); free(req); return -1; }
- pthread_detach(tid);
- return 0;
- }
-
-mDNSlocal void *TCPRequestForkFn(void *vptr)
- {
- TCPRequestArgs *req = vptr;
- PktMsg *in = NULL, *out = NULL;
- char buf[32];
-
- //!!!KRS if this read blocks indefinitely, we can run out of threads
- // read the request
- in = ReadTCPMsg(req->sd, NULL);
- if (!in)
- {
- LogMsg("TCPRequestForkFn: Could not read message from %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
- goto cleanup;
- }
-
- VLog("Received TCP request: %d bytes from %s", in->len, inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
- // create the reply
- out = HandleRequest(in, req->d);
- if (!out)
- {
- LogMsg("TCPRequestForkFn: No reply for client %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
- goto cleanup;
- }
-
- // deliver reply to client
- if (SendTCPMsg(req->sd, out) < 0)
- {
- LogMsg("TCPRequestForkFn: Unable to send reply to client %s", inet_ntop(AF_INET, &req->cliaddr.sin_addr, buf, 32));
- goto cleanup;
- }
-
- cleanup:
- free(req);
- if (in) free(in);
- if (out) free(out);
- pthread_exit(NULL);
- }
-
-mDNSlocal int RecvTCPRequest(int sd, DaemonInfo *d)
- {
- TCPRequestArgs *req;
- pthread_t tid;
- unsigned int clilen = sizeof(req->cliaddr);
-
- req = malloc(sizeof(TCPRequestArgs));
- if (!req) { LogErr("RecvTCPRequest", "malloc"); return -1; }
- bzero(req, sizeof(*req));
- req->d = d;
- req->sd = accept(sd, (struct sockaddr *)&req->cliaddr, &clilen);
- if (req->sd < 0) { LogErr("RecvTCPRequest", "accept"); return -1; }
- if (clilen != sizeof(req->cliaddr)) { Log("Client address of unknown size %d", clilen); free(req); return -1; }
- if (pthread_create(&tid, NULL, TCPRequestForkFn, req)) { LogErr("RecvTCPRequest", "pthread_create"); free(req); return -1; }
- pthread_detach(tid);
- return 0;
- }
-
-// main event loop
-// listen for incoming requests, periodically check table for expired records, respond to signals
-mDNSlocal int ListenForUpdates(DaemonInfo *d)
- {
- int err;
- int maxfdp1;
- fd_set rset;
- struct timeval timenow, timeout = { 0, 0 };
- long NextTableCheck = 0;
-
- VLog("Listening for requests...");
-
- FD_ZERO(&rset);
- maxfdp1 = d->tcpsd + 1;
- if (d->udpsd + 1 > maxfdp1) maxfdp1 = d->udpsd + 1;
- if (d->LLQEventListenSock + 1 > maxfdp1) maxfdp1 = d->LLQEventListenSock + 1;
-
- while(1)
- {
- // expire records if necessary, set timeout
- if (gettimeofday(&timenow, NULL)) { LogErr("ListenForUpdates", "gettimeofday"); return -1; }
- if (timenow.tv_sec >= NextTableCheck)
- {
- DeleteExpiredRecords(d);
- NextTableCheck = timenow.tv_sec + EXPIRATION_INTERVAL;
- }
- timeout.tv_sec = NextTableCheck - timenow.tv_sec;
-
- FD_SET(d->tcpsd, &rset);
- FD_SET(d->udpsd, &rset);
- FD_SET(d->LLQEventListenSock, &rset);
-
- err = select(maxfdp1, &rset, NULL, NULL, &timeout);
- if (err < 0)
- {
- if (errno == EINTR)
- {
- if (terminate) { DeleteExpiredRecords(d); return 0; }
- else if (dumptable) { PrintLeaseTable(d); PrintLLQTable(d); dumptable = 0; }
- else Log("Received unhandled signal - continuing");
- }
- else { LogErr("ListenForUpdates", "select"); return -1; }
- }
- else
- {
- if (FD_ISSET(d->tcpsd, &rset)) RecvTCPRequest(d->tcpsd, d);
- if (FD_ISSET(d->udpsd, &rset)) RecvUDPRequest(d->udpsd, d);
- if (FD_ISSET(d->LLQEventListenSock, &rset))
- {
- // clear signalling data off socket
- char buf[32];
- recv(d->LLQEventListenSock, buf, 32, 0);
- GenLLQEvents(d);
- }
- }
- }
- return 0;
- }
-
-// signal handler sets global variables, which are inspected by main event loop
-// (select automatically returns due to the handled signal)
-mDNSlocal void HndlSignal(int sig)
- {
- if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
- if (sig == INFO_SIGNAL) { dumptable = 1; return; }
- }
-
-int main(int argc, char *argv[])
- {
- pthread_t LLQtid;
- DaemonInfo *d;
-
- d = malloc(sizeof(*d));
- if (!d) { LogErr("main", "malloc"); exit(1); }
- bzero(d, sizeof(DaemonInfo));
-
- if (signal(SIGTERM, HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
- if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
- if (signal(SIGINT, HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
- if (signal(SIGPIPE, SIG_IGN ) == SIG_ERR) perror("Can't ignore SIGPIPE");
-
- if (ProcessArgs(argc, argv, d) < 0) exit(1);
-
- if (!foreground)
- {
- if (daemon(0,0))
- {
- LogErr("main", "daemon");
- fprintf(stderr, "Could not daemonize process, running in foreground");
- foreground = 1;
- }
- }
-
- if (InitLeaseTable(d) < 0) exit(1);
- if (SetupSockets(d) < 0) exit(1);
- if (SetUpdateSRV(d) < 0) exit(1);
-
- if (pthread_create(&LLQtid, NULL, LLQEventMonitor, d)) { LogErr("main", "pthread_create"); }
- else
- {
- pthread_detach(LLQtid);
- ListenForUpdates(d);
- }
-
- if (ClearUpdateSRV(d) < 0) exit(1); // clear update srv's even if ListenForUpdates or pthread_create returns an error
- free(d);
- exit(0);
-
- }
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*
* Formatting notes:
* This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
Change History (most recent first):
$Log: mDNSPosix.c,v $
-Revision 1.73 2005/10/11 21:31:46 cheshire
-<rdar://problem/4296177> Don't depend on IP_RECVTTL succeeding (not available on all platforms)
-
-Revision 1.72 2005/09/08 20:45:26 cheshire
-Default dot-local host name should be "Computer" not "Macintosh",
-since the machine this is running on is most likely NOT a Mac.
-
-Revision 1.71 2005/02/26 01:29:12 cheshire
-Ignore multicasts accidentally delivered to our unicast receiving socket
-
-Revision 1.70 2005/02/04 00:39:59 cheshire
-Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
-
-Revision 1.69 2004/12/18 02:03:28 cheshire
-Need to #include "dns_sd.h"
-
-Revision 1.68 2004/12/18 00:51:52 cheshire
-Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
-
-Revision 1.67 2004/12/17 23:37:48 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.66 2004/12/01 04:27:28 cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
-
-Revision 1.65 2004/11/30 22:37:01 cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.64 2004/11/23 03:39:47 cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
-
-Revision 1.63 2004/11/12 03:16:43 rpantos
-rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
-
-Revision 1.62 2004/10/28 03:24:42 cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
-
-Revision 1.61 2004/10/16 00:17:01 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.60 2004/09/26 23:20:36 ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
-
-Revision 1.59 2004/09/21 21:02:55 cheshire
-Set up ifname before calling mDNS_RegisterInterface()
-
-Revision 1.58 2004/09/17 01:08:54 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.57 2004/09/17 00:19:11 cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
-
-Revision 1.56 2004/09/17 00:15:56 cheshire
-Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast
-
-Revision 1.55 2004/09/16 00:24:49 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.54 2004/09/15 23:55:00 ksekar
-<rdar://problem/3800597> mDNSPosix should #include stdint.h
-
-Revision 1.53 2004/09/14 23:42:36 cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
-
-Revision 1.52 2004/08/25 16:42:13 ksekar
-Fix Posix build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
-hostname parameter.
+Revision 1.103 2007/10/02 19:31:17 cheshire
+In ParseDNSServers, should use strncasecmp for case-insensitive compare
-Revision 1.51 2004/08/14 03:22:42 cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.102 2007/09/12 19:23:17 cheshire
+Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
-Revision 1.50 2004/08/11 01:20:20 cheshire
-Declare private local functions using "mDNSlocal"
+Revision 1.101 2007/07/20 00:54:23 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Revision 1.49 2004/07/26 22:49:31 ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.100 2007/07/19 21:45:30 cheshire
+Fixed code spacing
-Revision 1.48 2004/07/20 01:47:36 rpantos
-NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
+Revision 1.99 2007/07/11 02:56:51 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Remove unused mDNSPlatformDefaultRegDomainChanged
-Revision 1.47 2004/06/25 00:26:27 rpantos
-Changes to fix the Posix build on Solaris.
+Revision 1.98 2007/06/20 01:10:13 cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-Revision 1.46 2004/05/13 04:54:20 ksekar
-Unified list copy/free code. Added symetric list for
+Revision 1.97 2007/04/26 00:35:16 cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
-Revision 1.45 2004/05/12 22:03:09 ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms. Changed call to return a copy of the list
-to avoid shared memory issues. Added a routine to free the list.
+Revision 1.96 2007/04/22 20:29:59 cheshire
+Fix locking error
-Revision 1.44 2004/04/21 02:49:11 cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
+Revision 1.95 2007/04/22 20:15:46 cheshire
+Add missing parameters for mDNSPosixEventCallback
-Revision 1.43 2004/04/14 23:09:29 ksekar
-Support for TSIG signed dynamic updates.
+Revision 1.94 2007/04/17 19:21:29 cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
-Revision 1.42 2004/04/09 17:43:04 cheshire
-Make sure to set the McastTxRx field so that duplicate suppression works correctly
+Revision 1.93 2007/04/16 20:49:40 cheshire
+Fix compile errors for mDNSPosix build
-Revision 1.41 2004/02/06 01:19:51 cheshire
-Conditionally exclude IPv6 code unless HAVE_IPV6 is set
+Revision 1.92 2007/04/05 20:40:37 cheshire
+Remove unused mDNSPlatformTCPGetFlags()
-Revision 1.40 2004/02/05 01:00:01 rpantos
-Fix some issues that turned up when building for FreeBSD.
+Revision 1.91 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-Revision 1.39 2004/01/28 21:12:15 cheshire
-Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
+Revision 1.90 2007/03/21 00:31:45 cheshire
+Remove unnecessary (and unimplemented) platform functions
-Revision 1.38 2004/01/27 20:15:23 cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
+Revision 1.89 2007/03/20 17:07:15 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-Revision 1.37 2004/01/24 05:12:03 cheshire
-<rdar://problem/3534352>: Need separate socket for issuing unicast queries
+Revision 1.88 2007/03/07 00:30:18 mkrochma
+<rdar://problem/5034370> POSIX: kDNSServiceInterfaceIndexAny not correctly handled
+Thanks goes to Aidan Williams of Audinate who did a lot of work in diagnosing this
-Revision 1.36 2004/01/24 04:59:16 cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
+Revision 1.87 2007/02/08 21:12:28 cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-Revision 1.35 2004/01/23 21:37:08 cheshire
-For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
+Revision 1.86 2007/01/05 08:30:52 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.34 2004/01/22 03:43:09 cheshire
-Export constants like mDNSInterface_LocalOnly so that the client layers can use them
+Revision 1.85 2007/01/04 23:12:20 cheshire
+Remove unused mDNSPlatformDefaultBrowseDomainChanged
-Revision 1.33 2004/01/21 21:54:20 cheshire
-<rdar://problem/3448144>: Don't try to receive unicast responses if we're not the first to bind to the UDP port
+Revision 1.84 2006/12/22 21:07:35 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.32 2004/01/20 01:49:28 rpantos
-Tweak error handling of last checkin a bit.
+Revision 1.83 2006/12/21 00:09:46 cheshire
+Use mDNSPlatformMemZero instead of bzero
-Revision 1.31 2004/01/20 01:39:27 rpantos
-Respond to If changes by rebuilding interface list.
+Revision 1.82 2006/12/19 22:43:55 cheshire
+Fix compiler warnings
-Revision 1.30 2003/12/11 19:40:36 cheshire
-Fix 'destAddr.type == senderAddr.type;' that should have said 'destAddr.type = senderAddr.type;'
+Revision 1.81 2006/08/14 23:24:46 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.29 2003/12/11 18:53:22 cheshire
-Fix compiler warning reported by Paul Guyot
+Revision 1.80 2006/07/22 03:05:33 cheshire
+Improve error reporting for socket creation failures
-Revision 1.28 2003/12/11 03:03:51 rpantos
-Clean up mDNSPosix so that it builds on OS X again.
+Revision 1.79 2006/07/06 00:02:16 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Revision 1.27 2003/12/08 20:47:02 rpantos
-Add support for mDNSResponder on Linux.
+Revision 1.78 2006/06/28 09:12:22 cheshire
+Added debugging message
-Revision 1.26 2003/11/14 20:59:09 cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
+Revision 1.77 2006/03/19 02:00:11 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-Revision 1.25 2003/10/30 19:25:49 cheshire
-Fix signed/unsigned warning on certain compilers
+Revision 1.76 2006/01/09 19:29:16 cheshire
+<rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
-Revision 1.24 2003/08/18 23:12:23 cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
+Revision 1.75 2006/01/05 22:04:57 cheshire
+<rdar://problem/4399479> Log error message when send fails with "operation not permitted"
-Revision 1.23 2003/08/12 19:56:26 cheshire
-Update to APSL 2.0
+Revision 1.74 2006/01/05 21:45:27 cheshire
+<rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
-Revision 1.22 2003/08/06 18:46:15 cheshire
-LogMsg() errors are serious -- always report them to stderr, regardless of debugging level
-
-Revision 1.21 2003/08/06 18:20:51 cheshire
-Makefile cleanup
-
-Revision 1.20 2003/08/05 23:56:26 cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-(Right now mDNSPosix.c just reports 255 -- we should fix this)
-
-Revision 1.19 2003/07/19 03:15:16 cheshire
-Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
-and add the obvious trivial implementations to each platform support layer
-
-Revision 1.18 2003/07/14 18:11:54 cheshire
-Fix stricter compiler warnings
-
-Revision 1.17 2003/07/13 01:08:38 cheshire
-There's not much point running mDNS over a point-to-point link; exclude those
-
-Revision 1.16 2003/07/02 21:19:59 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.15 2003/06/18 05:48:41 cheshire
-Fix warnings
-
-Revision 1.14 2003/05/26 03:21:30 cheshire
-Tidy up address structure naming:
-mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.13 2003/05/26 03:01:28 cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.12 2003/05/21 03:49:18 cheshire
-Fix warning
-
-Revision 1.11 2003/05/06 00:00:50 cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.10 2003/04/25 01:45:57 cheshire
-<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
-
-Revision 1.9 2003/03/20 21:10:31 cheshire
-Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
-
-Revision 1.8 2003/03/15 04:40:38 cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.7 2003/03/13 03:46:21 cheshire
-Fixes to make the code build on Linux
-
-Revision 1.6 2003/03/08 00:35:56 cheshire
-Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.5 2002/12/23 22:13:31 jgraessl
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.4 2002/09/27 01:47:45 cheshire
-Workaround for Linux 2.0 systems that don't have IP_PKTINFO
-
-Revision 1.3 2002/09/21 20:44:53 zarzycki
-Added APSL info
-
-Revision 1.2 2002/09/19 21:25:36 cheshire
-mDNS_snprintf() doesn't need to be in a separate file
-
-Revision 1.1 2002/09/17 06:24:34 cheshire
-First checkin
*/
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
#include "dns_sd.h"
// Context record for interface change callback
struct IfChangeRec
{
- int NotifySD;
- mDNS* mDNS;
+ int NotifySD;
+ mDNS *mDNS;
};
typedef struct IfChangeRec IfChangeRec;
{
case AF_INET:
{
- struct sockaddr_in* sin = (struct sockaddr_in*)sa;
+ struct sockaddr_in *sin = (struct sockaddr_in*)sa;
ipAddr->type = mDNSAddrType_IPv4;
ipAddr->ip.v4.NotAnInteger = sin->sin_addr.s_addr;
if (ipPort) ipPort->NotAnInteger = sin->sin_port;
#if HAVE_IPV6
case AF_INET6:
{
- struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
#ifndef NOT_HAVE_SA_LEN
assert(sin6->sin6_len == sizeof(*sin6));
#endif
assert(m != NULL);
assert(msg != NULL);
assert(end != NULL);
- assert( (((char *) end) - ((char *) msg)) > 0 );
+ assert((((char *) end) - ((char *) msg)) > 0);
assert(dstPort.NotAnInteger != 0);
if (dst->type == mDNSAddrType_IPv4)
if (err > 0) err = 0;
else if (err < 0)
{
- if (thisIntf)
- verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
- errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
- else
- verbosedebugf("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
+ static int MessageCount = 0;
+ // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+ if (!mDNSAddressIsAllDNSLinkGroup(dst))
+ if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
+
+ if (MessageCount < 1000)
+ {
+ MessageCount++;
+ if (thisIntf)
+ LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
+ errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
+ else
+ LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
+ }
}
return PosixErrorToStatus(err);
// so all we can do is just assume it's a multicast
#if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
- if ( (destAddr.NotAnInteger == 0) && (flags & MSG_MCAST) )
+ if ((destAddr.NotAnInteger == 0) && (flags & MSG_MCAST))
{
destAddr.type = senderAddr.type;
- if (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroupv4;
- else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroupv6;
+ if (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
+ else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroup_v6.ip.v6;
}
#endif
}
else
{
- if ( packetInfo.ipi_ifname[0] != 0 ) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
- else if ( packetInfo.ipi_ifindex != -1 ) reject = (packetInfo.ipi_ifindex != intf->index);
+ if (packetInfo.ipi_ifname[0] != 0) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
+ else if (packetInfo.ipi_ifindex != -1) reject = (packetInfo.ipi_ifindex != intf->index);
if (reject)
{
&senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
}
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context, int *descriptor)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port)
+ {
+ (void)m; // Unused
+ (void)flags; // Unused
+ (void)port; // Unused
+ return NULL;
+ }
+
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
+ {
+ (void)flags; // Unused
+ (void)sd; // Unused
+ return NULL;
+ }
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+ {
+ (void)sock; // Unused
+ return -1;
+ }
+
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+ TCPConnectionCallback callback, void *context)
{
+ (void)sock; // Unused
(void)dst; // Unused
(void)dstport; // Unused
(void)InterfaceID; // Unused
(void)callback; // Unused
(void)context; // Unused
- (void)descriptor; // Unused
return(mStatus_UnsupportedErr);
}
-mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
{
- (void)sd; // Unused
+ (void)sock; // Unused
}
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
{
- (void)sd; // Unused
+ (void)sock; // Unused
(void)buf; // Unused
- (void)buflen; // Unused
- return(0);
+ (void)buflen; // Unused
+ (void)closed; // Unused
+ return 0;
}
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
{
- (void)sd; // Unused
+ (void)sock; // Unused
(void)msg; // Unused
(void)len; // Unused
- return(0);
+ return 0;
+ }
+
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
+ {
+ (void)m; // Unused
+ (void)port; // Unused
+ return NULL;
+ }
+
+mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
+ {
+ (void)sock; // Unused
+ }
+
+mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
+ {
+ return(mStatus_UnsupportedErr);
+ }
+
+mDNSexport void mDNSPlatformTLSTearDownCerts(void)
+ {
}
#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark ***** Get/Free Search Domain List
+#pragma mark ***** DDNS Config Platform Functions
#endif
-mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
+mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
{
- static DNameListElem tmp;
- static mDNSBool init = mDNSfalse;
+ (void) m;
+ (void) setservers;
+ (void) fqdn;
+ (void) setsearch;
+ (void) RegDomains;
+ (void) BrowseDomains;
+ }
- if (!init)
- {
- MakeDomainNameFromDNSNameString(&tmp.name, "local.");
- tmp.next = NULL;
- init = mDNStrue;
- }
- return mDNS_CopyDNameList(&tmp);
+mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
+ {
+ (void) m;
+ (void) v4;
+ (void) v6;
+ (void) router;
+
+ return mStatus_UnsupportedErr;
}
-mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
+mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
{
- return NULL;
+ (void) dname;
+ (void) status;
}
#if COMPILER_LIKES_PRAGMA_MARK
mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
{
// On Unix we have no better name than the host name, so we just use that.
- GetUserSpecifiedRFC1034ComputerName( namelabel);
+ GetUserSpecifiedRFC1034ComputerName(namelabel);
}
mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
struct in_addr ina;
line[255]='\0'; // just to be safe
if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue; // it will skip whitespaces
- if (strncmp(keyword,"nameserver",10)) continue;
+ if (strncasecmp(keyword,"nameserver",10)) continue;
if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
{
mDNSAddr DNSAddr;
DNSAddr.type = mDNSAddrType_IPv4;
DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
- mDNS_AddDNSServer(m, &DNSAddr, NULL);
+ mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort);
numOfServers++;
}
}
assert(intfName != NULL);
intf = (PosixNetworkInterface*)(m->HostInterfaces);
- while ( (intf != NULL) && (strcmp(intf->intfName, intfName) != 0) )
+ while ((intf != NULL) && (strcmp(intf->intfName, intfName) != 0))
intf = (PosixNetworkInterface *)(intf->coreIntf.next);
return intf;
}
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
{
PosixNetworkInterface *intf;
assert(m != NULL);
if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
+ if (index == kDNSServiceInterfaceIndexAny ) return(mDNSInterface_Any);
intf = (PosixNetworkInterface*)(m->HostInterfaces);
- while ( (intf != NULL) && (mDNSu32) intf->index != index)
+ while ((intf != NULL) && (mDNSu32) intf->index != index)
intf = (PosixNetworkInterface *)(intf->coreIntf.next);
return (mDNSInterfaceID) intf;
}
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
{
PosixNetworkInterface *intf;
assert(m != NULL);
if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
+ if (id == mDNSInterface_Any ) return(kDNSServiceInterfaceIndexAny);
intf = (PosixNetworkInterface*)(m->HostInterfaces);
- while ( (intf != NULL) && (mDNSInterfaceID) intf != id)
+ while ((intf != NULL) && (mDNSInterfaceID) intf != id)
intf = (PosixNetworkInterface *)(intf->coreIntf.next);
return intf ? intf->index : 0;
while (m->HostInterfaces)
{
PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
- mDNS_DeregisterInterface(m, &intf->coreIntf);
+ mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse);
if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
FreePosixNetworkInterface(intf);
}
assert(*sktPtr == -1);
// Open the socket...
- if (intfAddr->sa_family == AF_INET ) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
#if HAVE_IPV6
else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
#endif
else return EINVAL;
- if (*sktPtr < 0) { err = errno; perror("socket"); }
+ if (*sktPtr < 0) { err = errno; perror((intfAddr->sa_family == AF_INET) ? "socket AF_INET" : "socket AF_INET6"); }
// ... with a shared UDP port, if it's for multicast receiving
if (err == 0 && port.NotAnInteger)
// Add multicast group membership on this interface
if (err == 0 && JoinMulticastGroup)
{
- imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+ imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
imr.imr_interface = ((struct sockaddr_in*)intfAddr)->sin_addr;
err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
// Add multicast group membership on this interface
if (err == 0 && JoinMulticastGroup)
{
- imr6.ipv6mr_multiaddr = *(const struct in6_addr*)&AllDNSLinkGroupv6;
+ imr6.ipv6mr_multiaddr = *(const struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
imr6.ipv6mr_interface = interfaceIndex;
+ //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
if (err < 0)
{
bindAddr6.sin6_family = AF_INET6;
bindAddr6.sin6_port = port.NotAnInteger;
bindAddr6.sin6_flowinfo = 0;
-// bindAddr6.sin6_addr.s_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket
+ bindAddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
bindAddr6.sin6_scope_id = 0;
err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
// Clean up
if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
- assert( (err == 0) == (*sktPtr != -1) );
+ assert((err == 0) == (*sktPtr != -1));
return err;
}
// The interface is all ready to go, let's register it with the mDNS core.
if (err == 0)
- err = mDNS_RegisterInterface(m, &intf->coreIntf, 0);
+ err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse);
// Clean up.
if (err == 0)
if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
}
- assert( (err == 0) == (intf != NULL) );
+ assert((err == 0) == (intf != NULL));
return err;
}
#if HAVE_IPV6
|| (i->ifi_addr->sa_family == AF_INET6)
#endif
- ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT) )
+ ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT))
{
if (i->ifi_flags & IFF_LOOPBACK)
{
// loopback interface. This allows self-discovery if no interfaces are configured.
// Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
// In the interim, we skip loopback interface only if we found at least one v4 interface to use
- // if ( (m->HostInterfaces == NULL) && (firstLoopback != NULL) )
- if ( !foundav4 && firstLoopback )
+ // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
+ if (!foundav4 && firstLoopback)
(void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
}
// See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
// Open a socket that will receive interface change notifications
-mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
+mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
{
mStatus err = mStatus_NoError;
struct sockaddr_nl snl;
int sock;
int ret;
- sock = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock < 0)
return errno;
// Configure read to be non-blocking because inbound msg size is not known in advance
- (void) fcntl( sock, F_SETFL, O_NONBLOCK);
+ (void) fcntl(sock, F_SETFL, O_NONBLOCK);
/* Subscribe the socket to Link & IP addr notifications. */
- bzero( &snl, sizeof snl);
+ mDNSPlatformMemZero(&snl, sizeof snl);
snl.nl_family = AF_NETLINK;
snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
- ret = bind( sock, (struct sockaddr *) &snl, sizeof snl);
- if ( 0 == ret)
+ ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
+ if (0 == ret)
*pFD = sock;
else
err = errno;
}
#if MDNS_DEBUGMSGS
-mDNSlocal void PrintNetLinkMsg( const struct nlmsghdr *pNLMsg)
+mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
{
const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
- printf( "nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
- pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[ pNLMsg->nlmsg_type] : kNLRtMsgTypes[ pNLMsg->nlmsg_type - RTM_BASE],
+ printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
+ pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE],
pNLMsg->nlmsg_flags);
- if ( RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
+ if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
{
- struct ifinfomsg *pIfInfo = (struct ifinfomsg*) NLMSG_DATA( pNLMsg);
- printf( "ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
+ struct ifinfomsg *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
+ printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
}
- else if ( RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
+ else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
{
- struct ifaddrmsg *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA( pNLMsg);
- printf( "ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
+ struct ifaddrmsg *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
+ printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
pIfAddr->ifa_index, pIfAddr->ifa_flags);
}
- printf( "\n");
+ printf("\n");
}
#endif
-mDNSlocal mDNSu32 ProcessRoutingNotification( int sd)
+mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
// Read through the messages on sd and if any indicate that any interface records should
// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
{
ssize_t readCount;
- char buff[ 4096];
+ char buff[4096];
struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff;
mDNSu32 result = 0;
// enough to hold all pending data and so avoid message fragmentation.
// (Note that FIONREAD is not supported on AF_NETLINK.)
- readCount = read( sd, buff, sizeof buff);
- while ( 1)
+ readCount = read(sd, buff, sizeof buff);
+ while (1)
{
// Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
// If not, discard already-processed messages in buffer and read more data.
- if ( ( (char*) &pNLMsg[1] > ( buff + readCount)) || // i.e. *pNLMsg extends off end of buffer
- ( (char*) pNLMsg + pNLMsg->nlmsg_len > ( buff + readCount)))
+ if (((char*) &pNLMsg[1] > (buff + readCount)) || // i.e. *pNLMsg extends off end of buffer
+ ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
{
- if ( buff < (char*) pNLMsg) // we have space to shuffle
+ if (buff < (char*) pNLMsg) // we have space to shuffle
{
// discard processed data
- readCount -= ( (char*) pNLMsg - buff);
- memmove( buff, pNLMsg, readCount);
+ readCount -= ((char*) pNLMsg - buff);
+ memmove(buff, pNLMsg, readCount);
pNLMsg = (struct nlmsghdr*) buff;
// read more data
- readCount += read( sd, buff + readCount, sizeof buff - readCount);
+ readCount += read(sd, buff + readCount, sizeof buff - readCount);
continue; // spin around and revalidate with new readCount
}
else
}
#if MDNS_DEBUGMSGS
- PrintNetLinkMsg( pNLMsg);
+ PrintNetLinkMsg(pNLMsg);
#endif
// Process the NetLink message
- if ( pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
- result |= 1 << ((struct ifinfomsg*) NLMSG_DATA( pNLMsg))->ifi_index;
- else if ( pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
- result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA( pNLMsg))->ifa_index;
+ if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
+ result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
+ else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
+ result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
// Advance pNLMsg to the next message in the buffer
- if ( ( pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
+ if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
{
- ssize_t len = readCount - ( (char*)pNLMsg - buff);
- pNLMsg = NLMSG_NEXT( pNLMsg, len);
+ ssize_t len = readCount - ((char*)pNLMsg - buff);
+ pNLMsg = NLMSG_NEXT(pNLMsg, len);
}
else
break; // all done!
#else // USES_NETLINK
// Open a socket that will receive interface change notifications
-mDNSlocal mStatus OpenIfNotifySocket( int *pFD)
+mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
{
- *pFD = socket( AF_ROUTE, SOCK_RAW, 0);
+ *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
- if ( *pFD < 0)
+ if (*pFD < 0)
return mStatus_UnknownErr;
// Configure read to be non-blocking because inbound msg size is not known in advance
- (void) fcntl( *pFD, F_SETFL, O_NONBLOCK);
+ (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
return mStatus_NoError;
}
#if MDNS_DEBUGMSGS
-mDNSlocal void PrintRoutingSocketMsg( const struct ifa_msghdr *pRSMsg)
+mDNSlocal void PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
{
const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
"RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
- printf( "ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[ pRSMsg->ifam_type], index);
+ printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
}
#endif
-mDNSlocal mDNSu32 ProcessRoutingNotification( int sd)
+mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
// Read through the messages on sd and if any indicate that any interface records should
// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
{
ssize_t readCount;
- char buff[ 4096];
+ char buff[4096];
struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff;
mDNSu32 result = 0;
- readCount = read( sd, buff, sizeof buff);
- if ( readCount < (ssize_t) sizeof( struct ifa_msghdr))
+ readCount = read(sd, buff, sizeof buff);
+ if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
return mStatus_UnsupportedErr; // cannot decipher message
#if MDNS_DEBUGMSGS
- PrintRoutingSocketMsg( pRSMsg);
+ PrintRoutingSocketMsg(pRSMsg);
#endif
// Process the message
- if ( pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
+ if (pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
pRSMsg->ifam_type == RTM_IFINFO)
{
- if ( pRSMsg->ifam_type == RTM_IFINFO)
+ if (pRSMsg->ifam_type == RTM_IFINFO)
result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
else
result |= 1 << pRSMsg->ifam_index;
#endif // USES_NETLINK
// Called when data appears on interface change notification socket
-mDNSlocal void InterfaceChangeCallback( void *context)
+mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
{
IfChangeRec *pChgRec = (IfChangeRec*) context;
fd_set readFDs;
mDNSu32 changedInterfaces = 0;
struct timeval zeroTimeout = { 0, 0 };
-
- FD_ZERO( &readFDs);
- FD_SET( pChgRec->NotifySD, &readFDs);
+
+ (void)fd; // Unused
+ (void)filter; // Unused
+
+ FD_ZERO(&readFDs);
+ FD_SET(pChgRec->NotifySD, &readFDs);
do
{
- changedInterfaces |= ProcessRoutingNotification( pChgRec->NotifySD);
+ changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
}
- while ( 0 < select( pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
+ while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
// Currently we rebuild the entire interface list whenever any interface change is
// detected. If this ever proves to be a performance issue in a multi-homed
// configuration, more care should be paid to changedInterfaces.
- if ( changedInterfaces)
- mDNSPlatformPosixRefreshInterfaceList( pChgRec->mDNS);
+ if (changedInterfaces)
+ mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
}
// Register with either a Routing Socket or RtNetLink to listen for interface changes.
mStatus err;
IfChangeRec *pChgRec;
- pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate( sizeof *pChgRec);
- if ( pChgRec == NULL)
+ pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
+ if (pChgRec == NULL)
return mStatus_NoMemoryErr;
pChgRec->mDNS = m;
- err = OpenIfNotifySocket( &pChgRec->NotifySD);
- if ( err == 0)
- err = mDNSPosixAddFDToEventLoop( pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
+ err = OpenIfNotifySocket(&pChgRec->NotifySD);
+ if (err == 0)
+ err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
return err;
}
if (err == mStatus_NoError) err = SetupInterfaceList(m);
// Tell mDNS core about DNS Servers
+ mDNS_Lock(m);
if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
+ mDNS_Unlock(m);
if (err == mStatus_NoError)
{
err = WatchForInterfaceChange(m);
// Failure to observe interface changes is non-fatal.
- if ( err != mStatus_NoError)
+ if (err != mStatus_NoError)
{
fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
err = mStatus_NoError;
// mDNS core calls this routine to copy C strings.
// On the Posix platform this maps directly to the ANSI C strcpy.
-mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst)
+mDNSexport void mDNSPlatformStrCopy(void *dst, const void *src)
{
strcpy((char *)dst, (char *)src);
}
// mDNS core calls this routine to copy memory.
// On the Posix platform this maps directly to the ANSI C memcpy.
-mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len)
+mDNSexport void mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
{
memcpy(dst, src, len);
}
// mDNS core calls this routine to test whether blocks of memory are byte-for-byte
// identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len)
+mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
{
return memcmp(dst, src, len) == 0;
}
// mDNS core calls this routine to clear blocks of memory.
// On the Posix platform this is a simple wrapper around ANSI C memset.
-mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len)
+mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
{
memset(dst, 0, len);
}
// and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
// This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
// and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
- return( (tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625) );
+ return((tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625));
}
mDNSexport mDNSs32 mDNSPlatformUTC(void)
}
// update gMaxFD
-mDNSlocal void DetermineMaxEventFD( void )
+mDNSlocal void DetermineMaxEventFD(void)
{
PosixEventSource *iSource;
gMaxFD = 0;
- for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
- if ( gMaxFD < iSource->fd)
+ for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ if (gMaxFD < iSource->fd)
gMaxFD = iSource->fd;
}
// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context)
+mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
{
PosixEventSource *newSource;
- if ( gEventSources.LinkOffset == 0)
- InitLinkedList( &gEventSources, offsetof( PosixEventSource, Next));
+ if (gEventSources.LinkOffset == 0)
+ InitLinkedList(&gEventSources, offsetof(PosixEventSource, Next));
- if ( fd >= (int) FD_SETSIZE || fd < 0)
+ if (fd >= (int) FD_SETSIZE || fd < 0)
return mStatus_UnsupportedErr;
- if ( callback == NULL)
+ if (callback == NULL)
return mStatus_BadParamErr;
- newSource = (PosixEventSource*) malloc( sizeof *newSource);
- if ( NULL == newSource)
+ newSource = (PosixEventSource*) malloc(sizeof *newSource);
+ if (NULL == newSource)
return mStatus_NoMemoryErr;
newSource->Callback = callback;
newSource->Context = context;
newSource->fd = fd;
- AddToTail( &gEventSources, newSource);
- FD_SET( fd, &gEventFDs);
+ AddToTail(&gEventSources, newSource);
+ FD_SET(fd, &gEventFDs);
DetermineMaxEventFD();
}
// Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixRemoveFDFromEventLoop( int fd)
+mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
{
PosixEventSource *iSource;
- for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
{
- if ( fd == iSource->fd)
+ if (fd == iSource->fd)
{
- FD_CLR( fd, &gEventFDs);
- RemoveFromList( &gEventSources, iSource);
- free( iSource);
+ FD_CLR(fd, &gEventFDs);
+ RemoveFromList(&gEventSources, iSource);
+ free(iSource);
DetermineMaxEventFD();
return mStatus_NoError;
}
}
// Simply note the received signal in gEventSignals.
-mDNSlocal void NoteSignal( int signum)
+mDNSlocal void NoteSignal(int signum)
{
- sigaddset( &gEventSignals, signum);
+ sigaddset(&gEventSignals, signum);
}
// Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
-mStatus mDNSPosixListenForSignalInEventLoop( int signum)
+mStatus mDNSPosixListenForSignalInEventLoop(int signum)
{
struct sigaction action;
mStatus err;
- bzero( &action, sizeof action); // more portable than member-wise assignment
+ mDNSPlatformMemZero(&action, sizeof action); // more portable than member-wise assignment
action.sa_handler = NoteSignal;
- err = sigaction( signum, &action, (struct sigaction*) NULL);
+ err = sigaction(signum, &action, (struct sigaction*) NULL);
- sigaddset( &gEventSignalSet, signum);
+ sigaddset(&gEventSignalSet, signum);
return err;
}
// Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
-mStatus mDNSPosixIgnoreSignalInEventLoop( int signum)
+mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
{
struct sigaction action;
mStatus err;
- bzero( &action, sizeof action); // more portable than member-wise assignment
+ mDNSPlatformMemZero(&action, sizeof action); // more portable than member-wise assignment
action.sa_handler = SIG_DFL;
- err = sigaction( signum, &action, (struct sigaction*) NULL);
+ err = sigaction(signum, &action, (struct sigaction*) NULL);
- sigdelset( &gEventSignalSet, signum);
+ sigdelset(&gEventSignalSet, signum);
return err;
}
// Do a single pass through the attendent event sources and dispatch any found to their callbacks.
// Return as soon as internal timeout expires, or a signal we're listening for is received.
-mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout,
+mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
{
fd_set listenFDs = gEventFDs;
struct timeval timeout = *pTimeout;
// Include the sockets that are listening to the wire in our select() set
- mDNSPosixGetFDSet( m, &fdMax, &listenFDs, &timeout); // timeout may get modified
- if ( fdMax < gMaxFD)
+ mDNSPosixGetFDSet(m, &fdMax, &listenFDs, &timeout); // timeout may get modified
+ if (fdMax < gMaxFD)
fdMax = gMaxFD;
- numReady = select( fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
+ numReady = select(fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
// If any data appeared, invoke its callback
- if ( numReady > 0)
+ if (numReady > 0)
{
PosixEventSource *iSource;
- (void) mDNSPosixProcessFDSet( m, &listenFDs); // call this first to process wire data for clients
+ (void) mDNSPosixProcessFDSet(m, &listenFDs); // call this first to process wire data for clients
- for ( iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
{
- if ( FD_ISSET( iSource->fd, &listenFDs))
+ if (FD_ISSET(iSource->fd, &listenFDs))
{
- iSource->Callback( iSource->Context);
+ iSource->Callback(iSource->fd, 0, iSource->Context);
break; // in case callback removed elements from gEventSources
}
}
else
*pDataDispatched = mDNSfalse;
- (void) sigprocmask( SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
+ (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
*pSignalsReceived = gEventSignals;
- sigemptyset( &gEventSignals);
- (void) sigprocmask( SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
+ sigemptyset(&gEventSignals);
+ (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
return mStatus_NoError;
}
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSPosix.h,v $
+Revision 1.19 2007/04/22 20:15:46 cheshire
+Add missing parameters for mDNSPosixEventCallback
+
+Revision 1.18 2006/08/14 23:24:47 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.17 2005/02/04 00:39:59 cheshire
Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout);
extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds);
-typedef void (*mDNSPosixEventCallback)( void *context);
+typedef void (*mDNSPosixEventCallback)(int fd, short filter, void *context);
extern mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context);
extern mStatus mDNSPosixRemoveFDFromEventLoop( int fd);
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSUNP.c,v $
+Revision 1.34 2006/08/14 23:24:47 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.33 2006/03/13 23:14:21 cheshire
+<rdar://problem/4427969> Compile problems on FreeBSD
+Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
+
+Revision 1.32 2005/12/21 02:56:43 cheshire
+<rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
+
+Revision 1.31 2005/12/21 02:46:05 cheshire
+<rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite
+
Revision 1.30 2005/11/29 20:03:02 mkrochma
Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
#include <unistd.h>
#include <stdio.h>
+/* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
+ macro, usually defined in <sys/param.h> or someplace like that, to make sure the
+ CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
+ should be set to the name of the header to include to get the ALIGN(P) macro.
+*/
+#ifdef NEED_ALIGN_MACRO
+#include NEED_ALIGN_MACRO
+#endif
+
/* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
other platforms don't even have that include file. So,
if we haven't yet got a definition, let's try to find
#endif
#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
-#include <netinet6/in6_var.h>
+#include <net/if_var.h>
+#include <netinet/in_var.h>
+// NOTE: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
#endif
#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
if(plen>bits_in_block) ones_in_block=bits_in_block;
else ones_in_block=plen;
block = ones & (ones << (bits_in_block-ones_in_block));
- i==0 ? sprintf(addr, "%x", block) :
- sprintf(addr, "%s:%x", addr, block);
+ i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
plen -= ones_in_block;
}
}
ifi->ifi_index = if_nametoindex(ifr->ifr_name);
#else
ifrcopy = *ifr;
+#ifdef SIOCGIFINDEX
if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
ifi->ifi_index = ifrcopy.ifr_index;
else
+#endif
ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
#endif
memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
#ifdef NOT_HAVE_DAEMON
#include <fcntl.h>
#include <sys/stat.h>
-#include <signal.h>
+#include <sys/signal.h>
int daemon(int nochdir, int noclose)
{
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSUNP.h,v $
+Revision 1.19 2006/08/14 23:24:47 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.18 2005/04/08 21:37:57 ksekar
<rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
#!/bin/sh
+# Emacs settings: -*- tab-width: 4 -*-
#
-# Linux /etc/init.d script to start/stop the mdnsd daemon.
-# Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
#
-# @APPLE_LICENSE_HEADER_START@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
+# http://www.apache.org/licenses/LICENSE-2.0
#
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
# limitations under the License.
-#
-# @APPLE_LICENSE_HEADER_END@
+#
+# Linux /etc/init.d script to start/stop the mdnsd daemon.
#
# $Log: mdnsd.sh,v $
+# Revision 1.9 2006/09/05 20:00:14 cheshire
+# Moved Emacs settings to second line of file
+#
+# Revision 1.8 2006/08/29 16:42:01 mkrochma
+# Fix POSIX startup script
+#
+# Revision 1.7 2006/08/14 23:24:47 cheshire
+# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+#
# Revision 1.6 2004/12/07 20:30:45 cheshire
# Fix start-stop-daemon for Suse Linux (don't use -s TERM)
#
/*
Format an address structure as a string appropriate for DNS reverse (PTR)
- lookup for AF_INET6. Output is in .ip6.int domain.
+ lookup for AF_INET6. Output is in .ip6.arpa domain.
Parameters
prefixlen
#define k_aliases_max 15
#define k_addrs_max 15
-const int k_mdnsd_intfs_local = 0;
- // Tell mdnsd to perform lookups only using link-local interfaces.
- /*
- Currently, this feature is buggy. 0 will actually cause mdnsd to
- do what it thinks is best. Unfortunately, this is to lookup 'local'
- addresses locally and remote addresses via the DNS. Thus, lookups
- for non-"local" addresses via mdns will not work correctly.
-
- Apple is currently modifying mdnsd to allow a special interface id
- (expected value -2) to mean "always lookup locally". This constant
- should be changed once the change is made.
-
- AW - 16 June 2004
- */
-
-
typedef struct buf_header
{
char hostname [k_hostname_maxlen + 1];
switch (af)
{
case AF_INET:
- rrtype = T_A;
+ rrtype = kDNSServiceType_A;
result->hostent->h_length = 4;
// Length of an A record
break;
case AF_INET6:
- rrtype = T_AAAA;
+ rrtype = kDNSServiceType_AAAA;
result->hostent->h_length = 16;
// Length of an AAAA record
break;
errcode =
DNSServiceQueryRecord (
&sdref,
- 0, // reserved flags field
- k_mdnsd_intfs_local, // all local interfaces
+ kDNSServiceFlagsForceMulticast, // force multicast query
+ kDNSServiceInterfaceIndexAny, // all interfaces
fullname, // full name to query for
rrtype, // resource record type
- C_IN, // internet class records
+ kDNSServiceClass_IN, // internet class records
mdns_lookup_callback, // callback
result // Context - result buffer
);
errcode =
DNSServiceQueryRecord (
&sdref,
- 0, // reserved flags field
- k_mdnsd_intfs_local, // all local interfaces
+ kDNSServiceFlagsForceMulticast, // force multicast query
+ kDNSServiceInterfaceIndexAny, // all interfaces
addr_str, // address string to query for
- T_PTR, // pointer RRs
- C_IN, // internet class records
+ kDNSServiceType_PTR, // pointer RRs
+ kDNSServiceClass_IN, // internet class records
mdns_lookup_callback, // callback
result // Context - result buffer
);
}
// If a PTR
- if (rrtype == T_PTR)
+ if (rrtype == kDNSServiceType_PTR)
{
if (callback_body_ptr (fullname, result, rdlen, rdata) < 0)
return;
{
"local",
"254.169.in-addr.arpa",
- "0.8.e.f.ip6.int",
- "0.8.e.f.ip6.arpa",
+ "8.e.f.ip6.int",
+ "8.e.f.ip6.arpa",
+ "9.e.f.ip6.int",
+ "9.e.f.ip6.arpa",
+ "a.e.f.ip6.int",
+ "a.e.f.ip6.arpa",
+ "b.e.f.ip6.int",
+ "b.e.f.ip6.arpa",
NULL
// Always null terminated
};
if (errcode)
{
// Critical error, give up
+ fclose(cf);
return errcode;
}
}
+ fclose (cf);
+
return 0;
}
{
switch (rrtype)
{
- case T_A:
+ case kDNSServiceType_A:
return AF_INET;
- case T_AAAA:
+ case kDNSServiceType_AAAA:
return AF_INET6;
default:
switch (af)
{
case AF_INET:
- return T_A;
+ return kDNSServiceType_A;
case AF_INET6:
- return T_AAAA;
+ return kDNSServiceType_AAAA;
default:
//return ns_t_invalid;
// divide prefixlen into nibbles, rounding up
// Special handling for first
- if (i / 2)
+ if (i % 2)
{
- curr += sprintf (curr, "%d.", (in_addr_a [i] >> 4) & 0x0F);
+ curr += sprintf (curr, "%d.", (in_addr_a [i/2] >> 4) & 0x0F);
}
i >>= 1;
// Convert i to bytes (divide by 2)
// Index into 'name'
const char * rdata_curr = rdata;
- // drop any leading whitespace rubbish
- while (isspace (*rdata_curr))
- {
- rdata_curr ++;
- if (rdata_curr > rdata + rdlen)
- {
- return DNS_RDATA_TO_NAME_BAD_FORMAT;
- }
- }
+ if (rdlen == 0) return DNS_RDATA_TO_NAME_BAD_FORMAT;
/*
In RDATA, a DNS name is stored as a series of labels.
# Applicable domains
domain local
-domain 0.8.e.f.ip6.int
-domain 0.8.e.f.ip6.arpa
domain 254.169.in-addr.arpa
+domain 8.e.f.ip6.int
+domain 9.e.f.ip6.int
+domain a.e.f.ip6.int
+domain b.e.f.ip6.int
+domain 8.e.f.ip6.arpa
+domain 9.e.f.ip6.arpa
+domain a.e.f.ip6.arpa
+domain b.e.f.ip6.arpa
#!/usr/bin/python
-
-# parselog.py, written and contributed by Kevin Marks
+# Emacs settings: -*- tab-width: 4 -*-
#
# Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
#
-# @APPLE_LICENSE_HEADER_START@
-#
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
-#
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
# limitations under the License.
#
-# @APPLE_LICENSE_HEADER_END@
+# parselog.py, written and contributed by Kevin Marks
#
-# Requires OS X 10.3 Panther for Python and Core Graphics Python APIs
+# Requires OS X 10.3 Panther or later, for Python and Core Graphics Python APIs
# Invoke from the command line with "parselog.py fname" where fname is a log file made by mDNSNetMonitor
#
# Caveats:
# Filled green circle: Normal answer Hollow green circle: Goodbye message (record going away)
# Hollow blue circle: Legacy query (from old client)
# $Log: parselog.py,v $
+# Revision 1.4 2006/09/05 20:00:14 cheshire
+# Moved Emacs settings to second line of file
+#
+# Revision 1.3 2006/08/14 23:24:47 cheshire
+# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+#
# Revision 1.2 2003/12/01 21:47:44 cheshire
# APSL
#
{9CE2568A-3170-41C6-9F20-A0188A9EC114} = {9CE2568A-3170-41C6-9F20-A0188A9EC114}\r
EndProjectSection\r
EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel (Vista)", "mDNSWindows\ControlPanel\ControlPanelExe.vcproj", "{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
+ ProjectSection(ProjectDependencies) = postProject\r
+ EndProjectSection\r
+EndProject\r
Global\r
GlobalSection(SolutionConfiguration) = preSolution\r
Debug = Debug\r
Release = Release\r
EndGlobalSection\r
+ GlobalSection(ProjectDependencies) = postSolution\r
+ EndGlobalSection\r
GlobalSection(ProjectConfiguration) = postSolution\r
{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug.ActiveCfg = Debug|Win32\r
{AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug.Build.0 = Debug|Win32\r
{A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug.Build.0 = Debug|Win32\r
{A987A0C1-344F-475C-869C-F082EB11EEBA}.Release.ActiveCfg = Release|Win32\r
{A987A0C1-344F-475C-869C-F082EB11EEBA}.Release.Build.0 = Release|Win32\r
+ {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug.ActiveCfg = Debug|Win32\r
+ {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug.Build.0 = Debug|Win32\r
+ {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release.ActiveCfg = Release|Win32\r
+ {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release.Build.0 = Release|Win32\r
EndGlobalSection\r
GlobalSection(ExtensibilityGlobals) = postSolution\r
EndGlobalSection\r
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: CommonServices.h,v $
+Revision 1.8 2007/01/17 19:16:59 cheshire
+Only define ssize_t if it's not already defined
+
+Revision 1.7 2007/01/16 23:00:45 cheshire
+Don't need to include CoreServices.h
+
+Revision 1.6 2006/08/24 22:41:53 herscher
+<rdar://problem/4580067> POSIX: dnsextd_parser doesn't compile on Linux
+
+Revision 1.5 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.4 2006/07/05 22:43:21 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+
+Revision 1.3 2004/04/08 09:27:12 bradley
+Added macro for portable specification of callback calling conventions.
+
+Revision 1.2 2004/03/07 05:53:39 bradley
+Fixed NumVersion extraction macros. Updated error code mappings to match latest internal version.
+
+Revision 1.1 2004/01/30 02:25:59 bradley
+Common Services and portability support for various platforms.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @header CommonServices
+
+ Common Services for Mac OS X, Linux, Palm, VxWorks, Windows, and Windows CE.
+*/
+
+#ifndef __COMMON_SERVICES__
+#define __COMMON_SERVICES__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#if 0
+#pragma mark == Target ==
+#endif
+
+//===========================================================================================================================
+// Target
+//===========================================================================================================================
+
+// Macintosh
+
+#if( !defined( TARGET_OS_MAC ) )
+ #if( ( macintosh || __MACH__ ) && !KERNEL )
+ // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
+ #else
+ #define TARGET_OS_MAC 0
+ #endif
+#endif
+
+#if( !defined( TARGET_API_MAC_OSX_KERNEL ) )
+ #if( __MACH__ && KERNEL )
+ #define TARGET_API_MAC_OSX_KERNEL 1
+ #else
+ #define TARGET_API_MAC_OSX_KERNEL 0
+ #endif
+#endif
+
+// Linux
+
+#if( !defined( TARGET_OS_LINUX ) )
+ #if( defined( __linux__ ) )
+ #define TARGET_OS_LINUX 1
+ #else
+ #define TARGET_OS_LINUX 0
+ #endif
+#endif
+
+// Palm
+
+#if( !defined( TARGET_OS_PALM ) )
+ #if( defined( __PALMOS_TRAPS__ ) || defined( __PALMOS_ARMLET__ ) )
+ #define TARGET_OS_PALM 1
+ #else
+ #define TARGET_OS_PALM 0
+ #endif
+#endif
+
+// VxWorks
+
+#if( !defined( TARGET_OS_VXWORKS ) )
+
+ // No predefined macro for VxWorks so just assume VxWorks if nothing else is set.
+
+ #if( !macintosh && !__MACH__ && !defined( __linux__ ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
+ #define TARGET_OS_VXWORKS 1
+ #else
+ #define TARGET_OS_VXWORKS 0
+ #endif
+#endif
+
+// Windows
+
+#if( !defined( TARGET_OS_WIN32 ) )
+ #if( macintosh || __MACH__ )
+ // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
+ #else
+ #if( defined( _WIN32 ) )
+ #define TARGET_OS_WIN32 1
+ #else
+ #define TARGET_OS_WIN32 0
+ #endif
+ #endif
+#endif
+
+// Windows CE
+
+#if( !defined( TARGET_OS_WINDOWS_CE ) )
+ #if( defined( _WIN32_WCE ) )
+ #define TARGET_OS_WINDOWS_CE 1
+ #else
+ #define TARGET_OS_WINDOWS_CE 0
+ #endif
+#endif
+
+#if 0
+#pragma mark == Includes ==
+#endif
+
+//===========================================================================================================================
+// Includes
+//===========================================================================================================================
+
+#if( !KERNEL )
+ #include <stddef.h>
+#endif
+
+#if( ( macintosh || __MACH__ ) && !KERNEL )
+
+ #if( defined( __MWERKS__ ) )
+ #if( __option( c9x ) )
+ #include <stdbool.h>
+ #endif
+ #else
+ #include <stdbool.h>
+ #endif
+
+ #include <stdint.h>
+
+ #if( __MACH__ )
+
+ // Mac OS X
+
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <fcntl.h>
+ #include <pthread.h>
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+ #include <unistd.h>
+
+ #else
+
+ // Classic Mac OS
+
+ #include <ConditionalMacros.h>
+ #include <MacTypes.h>
+
+ #endif
+
+#elif( KERNEL )
+
+ // Mac OS X Kernel
+
+ #include <stdint.h>
+
+ #include <libkern/OSTypes.h>
+ #include <sys/types.h>
+
+#elif( TARGET_OS_LINUX )
+
+ // Linux (no special includes yet).
+
+#elif( TARGET_OS_PALM )
+
+ // Palm (no special includes yet).
+
+#elif( TARGET_OS_VXWORKS )
+
+ // VxWorks
+
+ #include "vxWorks.h"
+
+#elif( TARGET_OS_WIN32 )
+
+ // Windows
+
+ #if( !defined( WIN32_WINDOWS ) )
+ #define WIN32_WINDOWS 0x0401
+ #endif
+
+ #if( !defined( _WIN32_WINDOWS ) )
+ #define _WIN32_WINDOWS 0x0401
+ #endif
+
+ #if( !defined( WIN32_LEAN_AND_MEAN ) )
+ #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
+ #endif
+
+ #if( defined( __MWERKS__ ) )
+
+ #if( __option( c9x ) )
+ #include <stdbool.h>
+ #endif
+
+ #include <stdint.h>
+
+ #elif( defined( _MSC_VER ) )
+
+ #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
+ #pragma warning( disable:4706 ) // Disable "assignment within conditional expression" for Microsoft headers.
+
+ #endif
+
+ #include <windows.h>
+ #include <winsock2.h>
+ #include <Ws2tcpip.h>
+
+ #if( defined( _MSC_VER ) )
+ #pragma warning( default:4706 )
+ #endif
+
+#else
+ #error unknown OS - update this file to support your OS
+#endif
+
+#if( !defined( TARGET_BUILD_MAIN ) )
+ #if( !TARGET_OS_VXWORKS )
+ #define TARGET_BUILD_MAIN 1
+ #endif
+#endif
+
+#if( __GNUC__ || !TARGET_OS_VXWORKS )
+ #define TARGET_LANGUAGE_C_LIKE 1
+#else
+ #define TARGET_LANGUAGE_C_LIKE 0
+#endif
+
+#if 0
+#pragma mark == CPU ==
+#endif
+
+//===========================================================================================================================
+// CPU
+//===========================================================================================================================
+
+// PowerPC
+
+#if( !defined( TARGET_CPU_PPC ) )
+ #if( defined( __ppc__ ) || defined( __PPC__ ) || defined( powerpc ) || defined( ppc ) || defined( _M_MPPC ) )
+ #define TARGET_CPU_PPC 1
+ #else
+ #define TARGET_CPU_PPC 0
+ #endif
+#endif
+
+// x86
+
+#if( !defined( TARGET_CPU_X86 ) )
+ #if( __INTEL__ || defined( __i386__ ) || defined( i386 ) || defined( intel ) || defined( _M_IX86 ) )
+ #define TARGET_CPU_X86 1
+ #else
+ #define TARGET_CPU_X86 0
+ #endif
+#endif
+
+// MIPS
+
+#if( !defined( TARGET_CPU_MIPS ) )
+ #if( __MIPS__ || defined( MIPS32 ) || defined( R3000 ) || defined( R4000 ) || defined( R4650 ) || defined( _M_MRX000 ) )
+ #define TARGET_CPU_MIPS 1
+ #else
+ #define TARGET_CPU_MIPS 0
+ #endif
+#endif
+
+#if( !defined( TARGET_CPU_PPC ) && !defined( TARGET_CPU_X86 ) && !defined( TARGET_CPU_MIPS ) )
+ #error unknown CPU - update this file to support your CPU
+#endif
+
+#if 0
+#pragma mark == Byte Order ==
+#endif
+
+//===========================================================================================================================
+// Byte Order
+//===========================================================================================================================
+
+// TARGET_RT_LITTLE_ENDIAN
+
+#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
+ #if( MIPSEL || IL_LITTLE_ENDIAN || defined( __LITTLE_ENDIAN__ ) || \
+ ( defined( BYTE_ORDER ) && defined( LITTLE_ENDIAN ) && ( BYTE_ORDER == LITTLE_ENDIAN ) ) || \
+ ( defined( _BYTE_ORDER ) && defined( _LITTLE_ENDIAN ) && ( _BYTE_ORDER == _LITTLE_ENDIAN ) ) || \
+ ( defined( __BYTE_ORDER ) && defined( __LITTLE_ENDIAN ) && ( __BYTE_ORDER == __LITTLE_ENDIAN ) ) || \
+ TARGET_CPU_X86 || ( defined( TARGET_RT_BIG_ENDIAN ) && !TARGET_RT_BIG_ENDIAN ) )
+ #define TARGET_RT_LITTLE_ENDIAN 1
+ #else
+ #define TARGET_RT_LITTLE_ENDIAN 0
+ #endif
+#endif
+
+// TARGET_RT_BIG_ENDIAN
+
+#if( !defined( TARGET_RT_BIG_ENDIAN ) )
+ #if( MIPSEB || IL_BIG_ENDIAN || defined( __BIG_ENDIAN__ ) || \
+ ( defined( BYTE_ORDER ) && defined( BIG_ENDIAN ) && ( BYTE_ORDER == BIG_ENDIAN ) ) || \
+ ( defined( _BYTE_ORDER ) && defined( _BIG_ENDIAN ) && ( _BYTE_ORDER == _BIG_ENDIAN ) ) || \
+ ( defined( __BYTE_ORDER ) && defined( __BIG_ENDIAN ) && ( __BYTE_ORDER == __BIG_ENDIAN ) ) || \
+ ( defined( TARGET_RT_LITTLE_ENDIAN ) && !TARGET_RT_LITTLE_ENDIAN ) )
+ #define TARGET_RT_BIG_ENDIAN 1
+ #else
+ #define TARGET_RT_BIG_ENDIAN 0
+ #endif
+#endif
+
+#if( defined( TARGET_RT_LITTLE_ENDIAN ) && !defined( TARGET_RT_BIG_ENDIAN ) )
+ #if( TARGET_RT_LITTLE_ENDIAN )
+ #define TARGET_RT_BIG_ENDIAN 0
+ #else
+ #define TARGET_RT_BIG_ENDIAN 1
+ #endif
+#endif
+
+#if( defined( TARGET_RT_BIG_ENDIAN ) && !defined( TARGET_RT_LITTLE_ENDIAN ) )
+ #if( TARGET_RT_BIG_ENDIAN )
+ #define TARGET_RT_LITTLE_ENDIAN 0
+ #else
+ #define TARGET_RT_LITTLE_ENDIAN 1
+ #endif
+#endif
+
+#if( !defined( TARGET_RT_LITTLE_ENDIAN ) || !defined( TARGET_RT_BIG_ENDIAN ) )
+ #error unknown byte order - update this file to support your byte order
+#endif
+
+// TARGET_RT_BYTE_ORDER
+
+#if( !defined( TARGET_RT_BYTE_ORDER_BIG_ENDIAN ) )
+ #define TARGET_RT_BYTE_ORDER_BIG_ENDIAN 1234
+#endif
+
+#if( !defined( TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN ) )
+ #define TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN 4321
+#endif
+
+#if( !defined( TARGET_RT_BYTE_ORDER ) )
+ #if( TARGET_RT_LITTLE_ENDIAN )
+ #define TARGET_RT_BYTE_ORDER TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN
+ #else
+ #define TARGET_RT_BYTE_ORDER TARGET_RT_BYTE_ORDER_BIG_ENDIAN
+ #endif
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+// Constants
+//===========================================================================================================================
+
+#if( !TARGET_OS_MAC )
+ #define CR '\r'
+#endif
+
+#define LF '\n'
+#define CRSTR "\r"
+#define LFSTR "\n"
+#define CRLF "\r\n"
+#define CRCR "\r\r"
+
+#if 0
+#pragma mark == Compatibility ==
+#endif
+
+//===========================================================================================================================
+// Compatibility
+//===========================================================================================================================
+
+// Macros to allow the same code to work on Windows and other sockets API-compatible platforms.
+
+#if( TARGET_OS_WIN32 )
+ #define close_compat( X ) closesocket( X )
+ #define errno_compat() (int) GetLastError()
+ #define set_errno_compat( X ) SetLastError( X )
+ #define EWOULDBLOCK_compat WSAEWOULDBLOCK
+ #define ETIMEDOUT_compat WSAETIMEDOUT
+ #define ENOTCONN_compat WSAENOTCONN
+ #define IsValidSocket( X ) ( ( X ) != INVALID_SOCKET )
+ #define kInvalidSocketRef INVALID_SOCKET
+ #if( TARGET_LANGUAGE_C_LIKE )
+ typedef SOCKET SocketRef;
+ #endif
+#else
+ #define close_compat( X ) close( X )
+ #define errno_compat() errno
+ #define set_errno_compat( X ) do { errno = ( X ); } while( 0 )
+ #define EWOULDBLOCK_compat EWOULDBLOCK
+ #define ETIMEDOUT_compat ETIMEDOUT
+ #define ENOTCONN_compat ENOTCONN
+ #define IsValidSocket( X ) ( ( X ) >= 0 )
+ #define kInvalidSocketRef -1
+ #if( TARGET_LANGUAGE_C_LIKE )
+ typedef int SocketRef;
+ #endif
+#endif
+
+// socklen_t is not defined on the following platforms so emulate it if not defined:
+//
+// - Pre-Panther Mac OS X. Panther defines SO_NOADDRERR so trigger off that.
+// - Windows SDK prior to 2003. 2003+ SDK's define EAI_AGAIN so trigger off that.
+// - VxWorks
+
+#if( TARGET_LANGUAGE_C_LIKE )
+ #if( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) || TARGET_OS_VXWORKS )
+ typedef int socklen_t;
+ #endif
+#endif
+
+// ssize_t is not defined on the following platforms so emulate it if not defined:
+//
+// - Mac OS X when not building with BSD headers
+// - Windows
+
+#if( TARGET_LANGUAGE_C_LIKE )
+ #if( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
+ typedef int ssize_t;
+ #endif
+#endif
+
+// sockaddr_storage is not supported on non-IPv6 machines so alias it to an IPv4-compatible structure.
+
+#if( TARGET_LANGUAGE_C_LIKE )
+ #if( !defined( AF_INET6 ) )
+ #define sockaddr_storage sockaddr_in
+ #define ss_family sin_family
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined SOCKADDR_IS_IP_LOOPBACK
+
+ @abstract Determines if a sockaddr is an IPv4 or IPv6 loopback address (if IPv6 is supported).
+*/
+
+#if( defined( AF_INET6 ) )
+ #define SOCKADDR_IS_IP_LOOPBACK( SA ) \
+ ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
+ ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) \
+ : ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET6 ) \
+ ? IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) \
+ : 0
+#else
+ #define SOCKADDR_IS_IP_LOOPBACK( SA ) \
+ ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
+ ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) \
+ : 0
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined SOCKADDR_IS_IP_LINK_LOCAL
+
+ @abstract Determines if a sockaddr is an IPv4 or IPv6 link-local address (if IPv6 is supported).
+*/
+
+#if( defined( AF_INET6 ) )
+ #define SOCKADDR_IS_IP_LINK_LOCAL( SA ) \
+ ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
+ ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
+ ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
+ : IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
+#else
+ #define SOCKADDR_IS_IP_LINK_LOCAL( SA ) \
+ ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
+ ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
+ ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
+ : 0 )
+#endif
+
+// _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking
+// resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to
+// CreateThread on Windows CE.
+
+#if( TARGET_OS_WINDOWS_CE )
+ #define _beginthreadex_compat( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR ) \
+ (uintptr_t) CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS, \
+ (LPDWORD) THREAD_ID_PTR )
+
+ #define _endthreadex_compat( RESULT ) ExitThread( (DWORD) RESULT )
+#elif( TARGET_OS_WIN32 )
+ #define _beginthreadex_compat _beginthreadex
+ #define _endthreadex_compat _endthreadex
+#endif
+
+// The C99 "inline" keyword is not supported by Microsoft compilers, but they do support __inline so map it when needed.
+
+#if( defined( _MSC_VER ) )
+ #define inline_compat __inline
+#else
+ #define inline_compat inline
+#endif
+
+// Calling conventions
+
+#if( !defined( CALLBACK_COMPAT ) )
+ #if( TARGET_OS_WIN32 || TARGET_OS_WINDOWS_CE )
+ #define CALLBACK_COMPAT CALLBACK
+ #else
+ #define CALLBACK_COMPAT
+ #endif
+#endif
+
+#if 0
+#pragma mark == Macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined kSizeCString
+
+ @abstract A meta-value to pass to supported routines to indicate the size should be calculated with strlen.
+*/
+
+#define kSizeCString ( (size_t) -1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined sizeof_array
+
+ @abstract Determines the number of elements in an array.
+*/
+
+#define sizeof_array( X ) ( sizeof( X ) / sizeof( X[ 0 ] ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined sizeof_element
+
+ @abstract Determines the size of an array element.
+*/
+
+#define sizeof_element( X ) sizeof( X[ 0 ] )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined sizeof_string
+
+ @abstract Determines the size of a constant C string, excluding the null terminator.
+*/
+
+#define sizeof_string( X ) ( sizeof( ( X ) ) - 1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined sizeof_field
+
+ @abstract Determines the size of a field of a type.
+*/
+
+#define sizeof_field( TYPE, FIELD ) sizeof( ( ( (TYPE *) 0 )->FIELD ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function RoundUp
+
+ @abstract Rounds X up to a multiple of Y.
+*/
+
+#define RoundUp( X, Y ) ( ( X ) + ( ( Y ) - ( ( X ) % ( Y ) ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function IsAligned
+
+ @abstract Returns non-zero if X is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
+*/
+
+#define IsAligned( X, Y ) ( ( ( X ) & ( ( Y ) - 1 ) ) == 0 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function IsFieldAligned
+
+ @abstract Returns non-zero if FIELD of type TYPE is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
+*/
+
+#define IsFieldAligned( X, TYPE, FIELD, Y ) IsAligned( ( (uintptr_t)( X ) ) + offsetof( TYPE, FIELD ), ( Y ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function AlignDown
+
+ @abstract Aligns X down to a Y byte boundary. Y must be a power of 2.
+*/
+
+#define AlignDown( X, Y ) ( ( X ) & ~( ( Y ) - 1 ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function AlignUp
+
+ @abstract Aligns X up to a Y byte boundary. Y must be a power of 2.
+*/
+
+#define AlignUp( X, Y ) ( ( ( X ) + ( ( Y ) - 1 ) ) & ~( ( Y ) - 1 ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function Min
+
+ @abstract Returns the lesser of X and Y.
+*/
+
+#if( !defined( Min ) )
+ #define Min( X, Y ) ( ( ( X ) < ( Y ) ) ? ( X ) : ( Y ) )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function Max
+
+ @abstract Returns the greater of X and Y.
+*/
+
+#if( !defined( Max ) )
+ #define Max( X, Y ) ( ( ( X ) > ( Y ) ) ? ( X ) : ( Y ) )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function InsertBits
+
+ @abstract Inserts BITS (both 0 and 1 bits) into X, controlled by MASK and SHIFT, and returns the result.
+
+ @discussion
+
+ MASK is the bitmask of the bits in the final position.
+ SHIFT is the number of bits to shift left for 1 to reach the first bit position of MASK.
+
+ For example, if you wanted to insert 0x3 into the leftmost 4 bits of a 32-bit value:
+
+ InsertBits( 0, 0x3, 0xF0000000U, 28 ) == 0x30000000
+*/
+
+#define InsertBits( X, BITS, MASK, SHIFT ) ( ( ( X ) & ~( MASK ) ) | ( ( ( BITS ) << ( SHIFT ) ) & ( MASK ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function ExtractBits
+
+ @abstract Extracts bits from X, controlled by MASK and SHIFT, and returns the result.
+
+ @discussion
+
+ MASK is the bitmask of the bits in the final position.
+ SHIFT is the number of bits to shift right to right justify MASK.
+
+ For example, if you had a 32-bit value (e.g. 0x30000000) wanted the left-most 4 bits (e.g. 3 in this example):
+
+ ExtractBits( 0x30000000U, 0xF0000000U, 28 ) == 0x3
+*/
+
+#define ExtractBits( X, MASK, SHIFT ) ( ( ( X ) >> ( SHIFT ) ) & ( ( MASK ) >> ( SHIFT ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function Stringify
+
+ @abstract Stringify's an expression.
+
+ @discussion
+
+ Stringify macros to process raw text passed via -D options to C string constants. The double-wrapping is necessary
+ because the C preprocessor doesn't perform its normal argument expansion pre-scan with stringified macros so the
+ -D macro needs to be expanded once via the wrapper macro then stringified so the raw text is stringified. Otherwise,
+ the replacement value would be used instead of the symbolic name (only for preprocessor symbols like #defines).
+
+ For example:
+
+ #define kMyConstant 1
+
+ printf( "%s", Stringify( kMyConstant ) ); // Prints "kMyConstant"
+ printf( "%s", StringifyExpansion( kMyConstant ) ); // Prints "1"
+
+ Non-preprocessor symbols do not have this issue. For example:
+
+ enum
+ {
+ kMyConstant = 1
+ };
+
+ printf( "%s", Stringify( kMyConstant ) ); // Prints "kMyConstant"
+ printf( "%s", StringifyExpansion( kMyConstant ) ); // Prints "kMyConstant"
+
+ See <http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html> for more info on C preprocessor pre-scanning.
+*/
+
+#define Stringify( X ) # X
+#define StringifyExpansion( X ) Stringify( X )
+
+#if 0
+#pragma mark == Types ==
+#endif
+
+#if( TARGET_LANGUAGE_C_LIKE )
+//===========================================================================================================================
+// Standard Types
+//===========================================================================================================================
+
+#if( !defined( INT8_MIN ) )
+
+ #define INT8_MIN SCHAR_MIN
+
+ #if( defined( _MSC_VER ) )
+
+ // C99 stdint.h not supported in VC++/VS.NET yet.
+
+ typedef INT8 int8_t;
+ typedef UINT8 uint8_t;
+ typedef INT16 int16_t;
+ typedef UINT16 uint16_t;
+ typedef INT32 int32_t;
+ typedef UINT32 uint32_t;
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+
+ #elif( TARGET_OS_VXWORKS && ( TORNADO_VERSION < 220 ) )
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+ #endif
+
+ typedef int8_t int_least8_t;
+ typedef int16_t int_least16_t;
+ typedef int32_t int_least32_t;
+ typedef int64_t int_least64_t;
+
+ typedef uint8_t uint_least8_t;
+ typedef uint16_t uint_least16_t;
+ typedef uint32_t uint_least32_t;
+ typedef uint64_t uint_least64_t;
+
+ typedef int8_t int_fast8_t;
+ typedef int16_t int_fast16_t;
+ typedef int32_t int_fast32_t;
+ typedef int64_t int_fast64_t;
+
+ typedef uint8_t uint_fast8_t;
+ typedef uint16_t uint_fast16_t;
+ typedef uint32_t uint_fast32_t;
+ typedef uint64_t uint_fast64_t;
+
+ #if( !defined( _MSC_VER ) || TARGET_OS_WINDOWS_CE )
+ typedef long int intptr_t;
+ typedef unsigned long int uintptr_t;
+ #endif
+
+#endif
+
+// Macros for minimum-width integer constants
+
+#if( !defined( INT8_C ) )
+ #define INT8_C( value ) value
+#endif
+
+#if( !defined( INT16_C ) )
+ #define INT16_C( value ) value
+#endif
+
+#if( !defined( INT32_C ) )
+ #define INT32_C( value ) value ## L
+#endif
+
+#if( !defined( INT64_C ) )
+ #if( defined( _MSC_VER ) )
+ #define INT64_C( value ) value ## i64
+ #else
+ #define INT64_C( value ) value ## LL
+ #endif
+#endif
+
+#if( !defined( UINT8_C ) )
+ #define UINT8_C( value ) value ## U
+#endif
+
+#if( !defined( UINT16_C ) )
+ #define UINT16_C( value ) value ## U
+#endif
+
+#if( !defined( UINT32_C ) )
+ #define UINT32_C( value ) value ## UL
+#endif
+
+#if( !defined( UINT64_C ) )
+ #if( defined( _MSC_VER ) )
+ #define UINT64_C( value ) value ## UI64
+ #else
+ #define UINT64_C( value ) value ## ULL
+ #endif
+#endif
+
+#if 0
+#pragma mark == bool ==
+#endif
+
+//===========================================================================================================================
+// Boolean Constants and Types
+//===========================================================================================================================
+
+// C++ defines bool, true, and false. Metrowerks allows this to be controlled by the "bool" option though.
+// C99 defines __bool_true_false_are_defined when bool, true, and false are defined.
+// MacTypes.h defines true and false (Mac builds only).
+//
+// Note: The Metrowerks has to be in its own block because Microsoft Visual Studio .NET does not completely
+// short-circuit and gets confused by the option( bool ) portion of the conditional.
+
+#if( defined( __MWERKS__ ) )
+
+ // Note: The following test is done on separate lines because CodeWarrior doesn't like it all on one line.
+
+ #if( !__bool_true_false_are_defined && ( !defined( __cplusplus ) || !__option( bool ) ) )
+ #define COMMON_SERVICES_NEEDS_BOOL 1
+ #else
+ #define COMMON_SERVICES_NEEDS_BOOL 0
+ #endif
+
+ // Workaround when building with CodeWarrior, but using the Apple stdbool.h header, which uses _Bool.
+
+ #if( __bool_true_false_are_defined && !defined( __cplusplus ) && !__option( c9x ) )
+ #define _Bool int
+ #endif
+
+ // Workaround when building with CodeWarrior for C++ with bool disabled and using the Apple stdbool.h header,
+ // which defines true and false to map to C++ true and false (which are not enabled). Serenity Now!
+
+ #if( __bool_true_false_are_defined && defined( __cplusplus ) && !__option( bool ) )
+ #define true 1
+ #define false 0
+ #endif
+#else
+ #define COMMON_SERVICES_NEEDS_BOOL ( !defined( __cplusplus ) && !__bool_true_false_are_defined )
+#endif
+
+#if( COMMON_SERVICES_NEEDS_BOOL )
+
+ typedef int bool;
+
+ #define bool bool
+
+ #if( !defined( __MACTYPES__ ) && !defined( true ) && !defined( false ) )
+ #define true 1
+ #define false 0
+ #endif
+
+ #define __bool_true_false_are_defined 1
+#endif
+
+// IOKit IOTypes.h typedef's bool if TYPE_BOOL is not defined so define it here to prevent redefinition by IOTypes.h.
+
+#if( TARGET_API_MAC_OSX_KERNEL )
+ #define TYPE_BOOL 1
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef CStr255
+
+ @abstract 255 character null-terminated (C-style) string.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+ typedef char CStr255[ 256 ];
+#endif
+
+#endif // TARGET_LANGUAGE_C_LIKE
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined TYPE_LONGLONG_NATIVE
+
+ @abstract Defines whether long long (or its equivalent) is natively supported or requires special libraries.
+*/
+
+#if( !defined( TYPE_LONGLONG_NATIVE ) )
+ #if( !TARGET_OS_VXWORKS )
+ #define TYPE_LONGLONG_NATIVE 1
+ #else
+ #define TYPE_LONGLONG_NATIVE 0
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined long_long_compat
+
+ @abstract Compatibility type to map to the closest thing to long long and unsigned long long.
+
+ @discussion
+
+ Neither long long nor unsigned long long are supported by Microsoft compilers, but they do support proprietary
+ "__int64" and "unsigned __int64" equivalents so map to those types if the real long long is not supported.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+ #if( TARGET_OS_WIN32 )
+ typedef __int64 long_long_compat;
+ typedef unsigned __int64 unsigned_long_long_compat;
+ #else
+ typedef signed long long long_long_compat;
+ typedef unsigned long long unsigned_long_long_compat;
+ #endif
+#endif
+
+#if 0
+#pragma mark == Errors ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @enum OSStatus
+
+ @abstract Status Code
+
+ @constant kNoErr 0 No error occurred.
+ @constant kInProgressErr 1 Operation in progress.
+ @constant kUnknownErr -6700 Unknown error occurred.
+ @constant kOptionErr -6701 Option was not acceptable.
+ @constant kSelectorErr -6702 Selector passed in is invalid or unknown.
+ @constant kExecutionStateErr -6703 Call made in the wrong execution state (e.g. called at interrupt time).
+ @constant kPathErr -6704 Path is invalid, too long, or otherwise not usable.
+ @constant kParamErr -6705 Parameter is incorrect, missing, or not appropriate.
+ @constant kParamCountErr -6706 Incorrect or unsupported number of parameters.
+ @constant kCommandErr -6707 Command invalid or not supported.
+ @constant kIDErr -6708 Unknown, invalid, or inappropriate identifier.
+ @constant kStateErr -6709 Not in appropriate state to perform operation.
+ @constant kRangeErr -6710 Index is out of range or not valid.
+ @constant kRequestErr -6711 Request was improperly formed or not appropriate.
+ @constant kResponseErr -6712 Response was incorrect or out of sequence.
+ @constant kChecksumErr -6713 Checksum does not match the actual data.
+ @constant kNotHandledErr -6714 Operation was not handled (or not handled completely).
+ @constant kVersionErr -6715 Version is not incorrect or not compatibile.
+ @constant kSignatureErr -6716 Signature did not match what was expected.
+ @constant kFormatErr -6717 Unknown, invalid, or inappropriate file/data format.
+ @constant kNotInitializedErr -6718 Action request before needed services were initialized.
+ @constant kAlreadyInitializedErr -6719 Attempt made to initialize when already initialized.
+ @constant kNotInUseErr -6720 Object not in use (e.g. cannot abort if not already in use).
+ @constant kInUseErr -6721 Object is in use (e.g. cannot reuse active param blocks).
+ @constant kTimeoutErr -6722 Timeout occurred.
+ @constant kCanceledErr -6723 Operation canceled (successful cancel).
+ @constant kAlreadyCanceledErr -6724 Operation has already been canceled.
+ @constant kCannotCancelErr -6725 Operation could not be canceled (maybe already done or invalid).
+ @constant kDeletedErr -6726 Object has already been deleted.
+ @constant kNotFoundErr -6727 Something was not found.
+ @constant kNoMemoryErr -6728 Not enough memory was available to perform the operation.
+ @constant kNoResourcesErr -6729 Resources unavailable to perform the operation.
+ @constant kDuplicateErr -6730 Duplicate found or something is a duplicate.
+ @constant kImmutableErr -6731 Entity is not changeable.
+ @constant kUnsupportedDataErr -6732 Data is unknown or not supported.
+ @constant kIntegrityErr -6733 Data is corrupt.
+ @constant kIncompatibleErr -6734 Data is not compatible or it is in an incompatible format.
+ @constant kUnsupportedErr -6735 Feature or option is not supported.
+ @constant kUnexpectedErr -6736 Error occurred that was not expected.
+ @constant kValueErr -6737 Value is not appropriate.
+ @constant kNotReadableErr -6738 Could not read or reading is not allowed.
+ @constant kNotWritableErr -6739 Could not write or writing is not allowed.
+ @constant kBadReferenceErr -6740 An invalid or inappropriate reference was specified.
+ @constant kFlagErr -6741 An invalid, inappropriate, or unsupported flag was specified.
+ @constant kMalformedErr -6742 Something was not formed correctly.
+ @constant kSizeErr -6743 Size was too big, too small, or not appropriate.
+ @constant kNameErr -6744 Name was not correct, allowed, or appropriate.
+ @constant kNotReadyErr -6745 Device or service is not ready.
+ @constant kReadErr -6746 Could not read.
+ @constant kWriteErr -6747 Could not write.
+ @constant kMismatchErr -6748 Something does not match.
+ @constant kDateErr -6749 Date is invalid or out-of-range.
+ @constant kUnderrunErr -6750 Less data than expected.
+ @constant kOverrunErr -6751 More data than expected.
+ @constant kEndingErr -6752 Connection, session, or something is ending.
+ @constant kConnectionErr -6753 Connection failed or could not be established.
+ @constant kAuthenticationErr -6754 Authentication failed or is not supported.
+ @constant kOpenErr -6755 Could not open file, pipe, device, etc.
+ @constant kTypeErr -6756 Incorrect or incompatible type (e.g. file, data, etc.).
+ @constant kSkipErr -6757 Items should be or was skipped.
+ @constant kNoAckErr -6758 No acknowledge.
+ @constant kCollisionErr -6759 Collision occurred (e.g. two on bus at same time).
+ @constant kBackoffErr -6760 Backoff in progress and operation intentionally failed.
+ @constant kNoAddressAckErr -6761 No acknowledge of address.
+ @constant kBusyErr -6762 Cannot perform because something is busy.
+ @constant kNoSpaceErr -6763 Not enough space to perform operation.
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+ #if( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
+ typedef int32_t OSStatus;
+ #endif
+#endif
+
+#define kNoErr 0
+#define kInProgressErr 1
+
+// Generic error codes are in the range -6700 to -6779.
+
+#define kGenericErrorBase -6700 // Starting error code for all generic errors.
+
+#define kUnknownErr -6700
+#define kOptionErr -6701
+#define kSelectorErr -6702
+#define kExecutionStateErr -6703
+#define kPathErr -6704
+#define kParamErr -6705
+#define kParamCountErr -6706
+#define kCommandErr -6707
+#define kIDErr -6708
+#define kStateErr -6709
+#define kRangeErr -6710
+#define kRequestErr -6711
+#define kResponseErr -6712
+#define kChecksumErr -6713
+#define kNotHandledErr -6714
+#define kVersionErr -6715
+#define kSignatureErr -6716
+#define kFormatErr -6717
+#define kNotInitializedErr -6718
+#define kAlreadyInitializedErr -6719
+#define kNotInUseErr -6720
+#define kInUseErr -6721
+#define kTimeoutErr -6722
+#define kCanceledErr -6723
+#define kAlreadyCanceledErr -6724
+#define kCannotCancelErr -6725
+#define kDeletedErr -6726
+#define kNotFoundErr -6727
+#define kNoMemoryErr -6728
+#define kNoResourcesErr -6729
+#define kDuplicateErr -6730
+#define kImmutableErr -6731
+#define kUnsupportedDataErr -6732
+#define kIntegrityErr -6733
+#define kIncompatibleErr -6734
+#define kUnsupportedErr -6735
+#define kUnexpectedErr -6736
+#define kValueErr -6737
+#define kNotReadableErr -6738
+#define kNotWritableErr -6739
+#define kBadReferenceErr -6740
+#define kFlagErr -6741
+#define kMalformedErr -6742
+#define kSizeErr -6743
+#define kNameErr -6744
+#define kNotReadyErr -6745
+#define kReadErr -6746
+#define kWriteErr -6747
+#define kMismatchErr -6748
+#define kDateErr -6749
+#define kUnderrunErr -6750
+#define kOverrunErr -6751
+#define kEndingErr -6752
+#define kConnectionErr -6753
+#define kAuthenticationErr -6754
+#define kOpenErr -6755
+#define kTypeErr -6756
+#define kSkipErr -6757
+#define kNoAckErr -6758
+#define kCollisionErr -6759
+#define kBackoffErr -6760
+#define kNoAddressAckErr -6761
+#define kBusyErr -6762
+#define kNoSpaceErr -6763
+
+#define kGenericErrorEnd -6779 // Last generic error code (inclusive)
+
+#if 0
+#pragma mark == Mac Compatibility ==
+#endif
+
+//===========================================================================================================================
+// Mac Compatibility
+//===========================================================================================================================
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @enum Duration
+
+ @abstract Type used to specify a duration of time.
+
+ @constant kDurationImmediate Indicates no delay/wait time.
+ @constant kDurationMicrosecond Microsecond units.
+ @constant kDurationMillisecond Millisecond units.
+ @constant kDurationSecond Second units.
+ @constant kDurationMinute Minute units.
+ @constant kDurationHour Hour units.
+ @constant kDurationDay Day units.
+ @constant kDurationForever Infinite period of time (no timeout).
+
+ @discussion
+
+ Duration values are intended to be multiplied by the specific interval to achieve an actual duration. For example,
+ to wait for 5 seconds you would use "5 * kDurationSecond".
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+ #if( !TARGET_OS_MAC )
+ typedef int32_t Duration;
+ #endif
+#endif
+
+#define kDurationImmediate 0L
+#define kDurationMicrosecond -1L
+#define kDurationMillisecond 1L
+#define kDurationSecond ( 1000L * kDurationMillisecond )
+#define kDurationMinute ( 60L * kDurationSecond )
+#define kDurationHour ( 60L * kDurationMinute )
+#define kDurationDay ( 24L * kDurationHour )
+#define kDurationForever 0x7FFFFFFFL
+
+// Seconds <-> Minutes <-> Hours <-> Days <-> Weeks <-> Months <-> Years conversions
+
+#define kNanosecondsPerMicrosecond 1000
+#define kNanosecondsPerMillisecond 1000000
+#define kNanosecondsPerSecond 1000000000
+#define kMicrosecondsPerSecond 1000000
+#define kMicrosecondsPerMillisecond 1000
+#define kMillisecondsPerSecond 1000
+#define kSecondsPerMinute 60
+#define kSecondsPerHour ( 60 * 60 ) // 3600
+#define kSecondsPerDay ( 60 * 60 * 24 ) // 86400
+#define kSecondsPerWeek ( 60 * 60 * 24 * 7 ) // 604800
+#define kMinutesPerHour 60
+#define kMinutesPerDay ( 60 * 24 ) // 1440
+#define kHoursPerDay 24
+#define kDaysPerWeek 7
+#define kWeeksPerYear 52
+#define kMonthsPerYear 12
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined VersionStages
+
+ @abstract NumVersion-style version stages.
+*/
+
+#define kVersionStageDevelopment 0x20
+#define kVersionStageAlpha 0x40
+#define kVersionStageBeta 0x60
+#define kVersionStageFinal 0x80
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function NumVersionBuild
+
+ @abstract Builds a 32-bit Mac-style NumVersion value (e.g. NumVersionBuild( 1, 2, 3, kVersionStageBeta, 4 ) -> 1.2.3b4).
+*/
+
+#define NumVersionBuild( MAJOR, MINOR, BUGFIX, STAGE, REV ) \
+ ( ( ( ( MAJOR ) & 0xFF ) << 24 ) | \
+ ( ( ( MINOR ) & 0x0F ) << 20 ) | \
+ ( ( ( BUGFIX ) & 0x0F ) << 16 ) | \
+ ( ( ( STAGE ) & 0xFF ) << 8 ) | \
+ ( ( ( REV ) & 0xFF ) ) )
+
+#define NumVersionExtractMajor( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 24 ) & 0xFF ) )
+#define NumVersionExtractMinorAndBugFix( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0xFF ) )
+#define NumVersionExtractMinor( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 20 ) & 0x0F ) )
+#define NumVersionExtractBugFix( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0x0F ) )
+#define NumVersionExtractStage( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 8 ) & 0xFF ) )
+#define NumVersionExtractRevision( VERSION ) ( (uint8_t)( ( VERSION ) & 0xFF ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function NumVersionCompare
+
+ @abstract Compares two NumVersion values and returns the following values:
+
+ left < right -> -1
+ left > right -> 1
+ left = right -> 0
+*/
+
+#if( TARGET_LANGUAGE_C_LIKE )
+ int NumVersionCompare( uint32_t inLeft, uint32_t inRight );
+#endif
+
+#if 0
+#pragma mark == Binary Constants ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined binary_4
+
+ @abstract Macro to generate an 4-bit constant using binary notation (e.g. binary_4( 1010 ) == 0xA).
+*/
+
+#define binary_4( a ) binary_4_hex_wrap( hex_digit4( a ) )
+#define binary_4_hex_wrap( a ) binary_4_hex( a )
+#define binary_4_hex( a ) ( 0x ## a )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined binary_8
+
+ @abstract Macro to generate an 8-bit constant using binary notation (e.g. binary_8( 01111011 ) == 0x7B).
+*/
+
+#define binary_8( a ) binary_8_hex_wrap( hex_digit8( a ) )
+#define binary_8_hex_wrap( a ) binary_8_hex( a )
+#define binary_8_hex( a ) ( 0x ## a )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined binary_16
+
+ @abstract Macro to generate an 16-bit constant using binary notation (e.g. binary_16( 01111011, 01111011 ) == 0x7B7B).
+*/
+
+#define binary_16( a, b ) binary_16_hex_wrap( hex_digit8( a ), hex_digit8( b ) )
+#define binary_16_hex_wrap( a, b ) binary_16_hex( a, b )
+#define binary_16_hex( a, b ) ( 0x ## a ## b )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined binary_32
+
+ @abstract Macro to generate an 32-bit constant using binary notation
+ (e.g. binary_32( 01111011, 01111011, 01111011, 01111011 ) == 0x7B7B7B7B).
+*/
+
+#define binary_32( a, b, c, d ) binary_32_hex_wrap( hex_digit8( a ), hex_digit8( b ), hex_digit8( c ), hex_digit8( d ) )
+#define binary_32_hex_wrap( a, b, c, d ) binary_32_hex( a, b, c, d )
+#define binary_32_hex( a, b, c, d ) ( 0x ## a ## b ## c ## d )
+
+// Binary Constant Helpers
+
+#define hex_digit8( a ) HEX_DIGIT_ ## a
+#define hex_digit4( a ) HEX_DIGIT_ ## 0000 ## a
+
+#define HEX_DIGIT_00000000 00
+#define HEX_DIGIT_00000001 01
+#define HEX_DIGIT_00000010 02
+#define HEX_DIGIT_00000011 03
+#define HEX_DIGIT_00000100 04
+#define HEX_DIGIT_00000101 05
+#define HEX_DIGIT_00000110 06
+#define HEX_DIGIT_00000111 07
+#define HEX_DIGIT_00001000 08
+#define HEX_DIGIT_00001001 09
+#define HEX_DIGIT_00001010 0A
+#define HEX_DIGIT_00001011 0B
+#define HEX_DIGIT_00001100 0C
+#define HEX_DIGIT_00001101 0D
+#define HEX_DIGIT_00001110 0E
+#define HEX_DIGIT_00001111 0F
+#define HEX_DIGIT_00010000 10
+#define HEX_DIGIT_00010001 11
+#define HEX_DIGIT_00010010 12
+#define HEX_DIGIT_00010011 13
+#define HEX_DIGIT_00010100 14
+#define HEX_DIGIT_00010101 15
+#define HEX_DIGIT_00010110 16
+#define HEX_DIGIT_00010111 17
+#define HEX_DIGIT_00011000 18
+#define HEX_DIGIT_00011001 19
+#define HEX_DIGIT_00011010 1A
+#define HEX_DIGIT_00011011 1B
+#define HEX_DIGIT_00011100 1C
+#define HEX_DIGIT_00011101 1D
+#define HEX_DIGIT_00011110 1E
+#define HEX_DIGIT_00011111 1F
+#define HEX_DIGIT_00100000 20
+#define HEX_DIGIT_00100001 21
+#define HEX_DIGIT_00100010 22
+#define HEX_DIGIT_00100011 23
+#define HEX_DIGIT_00100100 24
+#define HEX_DIGIT_00100101 25
+#define HEX_DIGIT_00100110 26
+#define HEX_DIGIT_00100111 27
+#define HEX_DIGIT_00101000 28
+#define HEX_DIGIT_00101001 29
+#define HEX_DIGIT_00101010 2A
+#define HEX_DIGIT_00101011 2B
+#define HEX_DIGIT_00101100 2C
+#define HEX_DIGIT_00101101 2D
+#define HEX_DIGIT_00101110 2E
+#define HEX_DIGIT_00101111 2F
+#define HEX_DIGIT_00110000 30
+#define HEX_DIGIT_00110001 31
+#define HEX_DIGIT_00110010 32
+#define HEX_DIGIT_00110011 33
+#define HEX_DIGIT_00110100 34
+#define HEX_DIGIT_00110101 35
+#define HEX_DIGIT_00110110 36
+#define HEX_DIGIT_00110111 37
+#define HEX_DIGIT_00111000 38
+#define HEX_DIGIT_00111001 39
+#define HEX_DIGIT_00111010 3A
+#define HEX_DIGIT_00111011 3B
+#define HEX_DIGIT_00111100 3C
+#define HEX_DIGIT_00111101 3D
+#define HEX_DIGIT_00111110 3E
+#define HEX_DIGIT_00111111 3F
+#define HEX_DIGIT_01000000 40
+#define HEX_DIGIT_01000001 41
+#define HEX_DIGIT_01000010 42
+#define HEX_DIGIT_01000011 43
+#define HEX_DIGIT_01000100 44
+#define HEX_DIGIT_01000101 45
+#define HEX_DIGIT_01000110 46
+#define HEX_DIGIT_01000111 47
+#define HEX_DIGIT_01001000 48
+#define HEX_DIGIT_01001001 49
+#define HEX_DIGIT_01001010 4A
+#define HEX_DIGIT_01001011 4B
+#define HEX_DIGIT_01001100 4C
+#define HEX_DIGIT_01001101 4D
+#define HEX_DIGIT_01001110 4E
+#define HEX_DIGIT_01001111 4F
+#define HEX_DIGIT_01010000 50
+#define HEX_DIGIT_01010001 51
+#define HEX_DIGIT_01010010 52
+#define HEX_DIGIT_01010011 53
+#define HEX_DIGIT_01010100 54
+#define HEX_DIGIT_01010101 55
+#define HEX_DIGIT_01010110 56
+#define HEX_DIGIT_01010111 57
+#define HEX_DIGIT_01011000 58
+#define HEX_DIGIT_01011001 59
+#define HEX_DIGIT_01011010 5A
+#define HEX_DIGIT_01011011 5B
+#define HEX_DIGIT_01011100 5C
+#define HEX_DIGIT_01011101 5D
+#define HEX_DIGIT_01011110 5E
+#define HEX_DIGIT_01011111 5F
+#define HEX_DIGIT_01100000 60
+#define HEX_DIGIT_01100001 61
+#define HEX_DIGIT_01100010 62
+#define HEX_DIGIT_01100011 63
+#define HEX_DIGIT_01100100 64
+#define HEX_DIGIT_01100101 65
+#define HEX_DIGIT_01100110 66
+#define HEX_DIGIT_01100111 67
+#define HEX_DIGIT_01101000 68
+#define HEX_DIGIT_01101001 69
+#define HEX_DIGIT_01101010 6A
+#define HEX_DIGIT_01101011 6B
+#define HEX_DIGIT_01101100 6C
+#define HEX_DIGIT_01101101 6D
+#define HEX_DIGIT_01101110 6E
+#define HEX_DIGIT_01101111 6F
+#define HEX_DIGIT_01110000 70
+#define HEX_DIGIT_01110001 71
+#define HEX_DIGIT_01110010 72
+#define HEX_DIGIT_01110011 73
+#define HEX_DIGIT_01110100 74
+#define HEX_DIGIT_01110101 75
+#define HEX_DIGIT_01110110 76
+#define HEX_DIGIT_01110111 77
+#define HEX_DIGIT_01111000 78
+#define HEX_DIGIT_01111001 79
+#define HEX_DIGIT_01111010 7A
+#define HEX_DIGIT_01111011 7B
+#define HEX_DIGIT_01111100 7C
+#define HEX_DIGIT_01111101 7D
+#define HEX_DIGIT_01111110 7E
+#define HEX_DIGIT_01111111 7F
+#define HEX_DIGIT_10000000 80
+#define HEX_DIGIT_10000001 81
+#define HEX_DIGIT_10000010 82
+#define HEX_DIGIT_10000011 83
+#define HEX_DIGIT_10000100 84
+#define HEX_DIGIT_10000101 85
+#define HEX_DIGIT_10000110 86
+#define HEX_DIGIT_10000111 87
+#define HEX_DIGIT_10001000 88
+#define HEX_DIGIT_10001001 89
+#define HEX_DIGIT_10001010 8A
+#define HEX_DIGIT_10001011 8B
+#define HEX_DIGIT_10001100 8C
+#define HEX_DIGIT_10001101 8D
+#define HEX_DIGIT_10001110 8E
+#define HEX_DIGIT_10001111 8F
+#define HEX_DIGIT_10010000 90
+#define HEX_DIGIT_10010001 91
+#define HEX_DIGIT_10010010 92
+#define HEX_DIGIT_10010011 93
+#define HEX_DIGIT_10010100 94
+#define HEX_DIGIT_10010101 95
+#define HEX_DIGIT_10010110 96
+#define HEX_DIGIT_10010111 97
+#define HEX_DIGIT_10011000 98
+#define HEX_DIGIT_10011001 99
+#define HEX_DIGIT_10011010 9A
+#define HEX_DIGIT_10011011 9B
+#define HEX_DIGIT_10011100 9C
+#define HEX_DIGIT_10011101 9D
+#define HEX_DIGIT_10011110 9E
+#define HEX_DIGIT_10011111 9F
+#define HEX_DIGIT_10100000 A0
+#define HEX_DIGIT_10100001 A1
+#define HEX_DIGIT_10100010 A2
+#define HEX_DIGIT_10100011 A3
+#define HEX_DIGIT_10100100 A4
+#define HEX_DIGIT_10100101 A5
+#define HEX_DIGIT_10100110 A6
+#define HEX_DIGIT_10100111 A7
+#define HEX_DIGIT_10101000 A8
+#define HEX_DIGIT_10101001 A9
+#define HEX_DIGIT_10101010 AA
+#define HEX_DIGIT_10101011 AB
+#define HEX_DIGIT_10101100 AC
+#define HEX_DIGIT_10101101 AD
+#define HEX_DIGIT_10101110 AE
+#define HEX_DIGIT_10101111 AF
+#define HEX_DIGIT_10110000 B0
+#define HEX_DIGIT_10110001 B1
+#define HEX_DIGIT_10110010 B2
+#define HEX_DIGIT_10110011 B3
+#define HEX_DIGIT_10110100 B4
+#define HEX_DIGIT_10110101 B5
+#define HEX_DIGIT_10110110 B6
+#define HEX_DIGIT_10110111 B7
+#define HEX_DIGIT_10111000 B8
+#define HEX_DIGIT_10111001 B9
+#define HEX_DIGIT_10111010 BA
+#define HEX_DIGIT_10111011 BB
+#define HEX_DIGIT_10111100 BC
+#define HEX_DIGIT_10111101 BD
+#define HEX_DIGIT_10111110 BE
+#define HEX_DIGIT_10111111 BF
+#define HEX_DIGIT_11000000 C0
+#define HEX_DIGIT_11000001 C1
+#define HEX_DIGIT_11000010 C2
+#define HEX_DIGIT_11000011 C3
+#define HEX_DIGIT_11000100 C4
+#define HEX_DIGIT_11000101 C5
+#define HEX_DIGIT_11000110 C6
+#define HEX_DIGIT_11000111 C7
+#define HEX_DIGIT_11001000 C8
+#define HEX_DIGIT_11001001 C9
+#define HEX_DIGIT_11001010 CA
+#define HEX_DIGIT_11001011 CB
+#define HEX_DIGIT_11001100 CC
+#define HEX_DIGIT_11001101 CD
+#define HEX_DIGIT_11001110 CE
+#define HEX_DIGIT_11001111 CF
+#define HEX_DIGIT_11010000 D0
+#define HEX_DIGIT_11010001 D1
+#define HEX_DIGIT_11010010 D2
+#define HEX_DIGIT_11010011 D3
+#define HEX_DIGIT_11010100 D4
+#define HEX_DIGIT_11010101 D5
+#define HEX_DIGIT_11010110 D6
+#define HEX_DIGIT_11010111 D7
+#define HEX_DIGIT_11011000 D8
+#define HEX_DIGIT_11011001 D9
+#define HEX_DIGIT_11011010 DA
+#define HEX_DIGIT_11011011 DB
+#define HEX_DIGIT_11011100 DC
+#define HEX_DIGIT_11011101 DD
+#define HEX_DIGIT_11011110 DE
+#define HEX_DIGIT_11011111 DF
+#define HEX_DIGIT_11100000 E0
+#define HEX_DIGIT_11100001 E1
+#define HEX_DIGIT_11100010 E2
+#define HEX_DIGIT_11100011 E3
+#define HEX_DIGIT_11100100 E4
+#define HEX_DIGIT_11100101 E5
+#define HEX_DIGIT_11100110 E6
+#define HEX_DIGIT_11100111 E7
+#define HEX_DIGIT_11101000 E8
+#define HEX_DIGIT_11101001 E9
+#define HEX_DIGIT_11101010 EA
+#define HEX_DIGIT_11101011 EB
+#define HEX_DIGIT_11101100 EC
+#define HEX_DIGIT_11101101 ED
+#define HEX_DIGIT_11101110 EE
+#define HEX_DIGIT_11101111 EF
+#define HEX_DIGIT_11110000 F0
+#define HEX_DIGIT_11110001 F1
+#define HEX_DIGIT_11110010 F2
+#define HEX_DIGIT_11110011 F3
+#define HEX_DIGIT_11110100 F4
+#define HEX_DIGIT_11110101 F5
+#define HEX_DIGIT_11110110 F6
+#define HEX_DIGIT_11110111 F7
+#define HEX_DIGIT_11111000 F8
+#define HEX_DIGIT_11111001 F9
+#define HEX_DIGIT_11111010 FA
+#define HEX_DIGIT_11111011 FB
+#define HEX_DIGIT_11111100 FC
+#define HEX_DIGIT_11111101 FD
+#define HEX_DIGIT_11111110 FE
+#define HEX_DIGIT_11111111 FF
+
+#if 0
+#pragma mark == Debugging ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function CommonServicesTest
+
+ @abstract Unit test.
+*/
+
+#if( DEBUG )
+ #if( TARGET_LANGUAGE_C_LIKE )
+ OSStatus CommonServicesTest( void );
+ #endif
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // __COMMON_SERVICES__
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: DebugServices.c,v $
+Revision 1.6 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.5 2004/09/17 01:08:57 cheshire
+Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
+ The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+ declared in that file are ONLY appropriate to single-address-space embedded applications.
+ For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+
+Revision 1.4 2004/04/15 08:59:08 bradley
+Removed deprecated debug and log levels and replaced them with modern equivalents.
+
+Revision 1.3 2004/04/08 09:29:55 bradley
+Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
+hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
+Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
+
+Revision 1.2 2004/03/07 05:59:34 bradley
+Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
+
+Revision 1.1 2004/01/30 02:27:30 bradley
+Debugging support for various platforms.
+
+
+ To Do:
+
+ - Use StackWalk on Windows to optionally print stack frames.
+*/
+
+#if 0
+#pragma mark == Includes ==
+#endif
+
+//===========================================================================================================================
+// Includes
+//===========================================================================================================================
+
+#if( !KERNEL )
+ #include <ctype.h>
+ #include <stdio.h>
+ #include <string.h>
+#endif
+
+#include "CommonServices.h"
+
+#include "DebugServices.h"
+
+#if( DEBUG )
+
+#if( TARGET_OS_VXWORKS )
+ #include "intLib.h"
+#endif
+
+#if( TARGET_OS_WIN32 )
+ #include <time.h>
+
+ #if( !TARGET_OS_WINDOWS_CE )
+ #include <fcntl.h>
+ #include <io.h>
+ #endif
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL )
+ #include <IOKit/IOLib.h>
+#endif
+
+// If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h.
+
+#if( defined( MDNS_DEBUGMSGS ) )
+ #include "mDNSEmbeddedAPI.h"
+#endif
+
+#if 0
+#pragma mark == Macros ==
+#endif
+
+//===========================================================================================================================
+// Macros
+//===========================================================================================================================
+
+#define DebugIsPrint( C ) ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) )
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+// Prototypes
+//===========================================================================================================================
+
+static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize );
+
+// fprintf
+
+#if( DEBUG_FPRINTF_ENABLED )
+ static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename );
+ static void DebugFPrintFPrint( char *inData, size_t inSize );
+#endif
+
+// iDebug (Mac OS X user and kernel)
+
+#if( DEBUG_IDEBUG_ENABLED )
+ static OSStatus DebugiDebugInit( void );
+ static void DebugiDebugPrint( char *inData, size_t inSize );
+#endif
+
+// kprintf (Mac OS X Kernel)
+
+#if( DEBUG_KPRINTF_ENABLED )
+ static void DebugKPrintFPrint( char *inData, size_t inSize );
+#endif
+
+// Mac OS X IOLog (Mac OS X Kernel)
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+ static void DebugMacOSXIOLogPrint( char *inData, size_t inSize );
+#endif
+
+// Mac OS X Log
+
+#if( TARGET_OS_MAC )
+ static OSStatus DebugMacOSXLogInit( void );
+ static void DebugMacOSXLogPrint( char *inData, size_t inSize );
+#endif
+
+// Windows Debugger
+
+#if( TARGET_OS_WIN32 )
+ static void DebugWindowsDebuggerPrint( char *inData, size_t inSize );
+#endif
+
+// Windows Event Log
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule );
+ static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize );
+#endif
+
+// DebugLib support
+
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+ static pascal void
+ DebugAssertOutputHandler(
+ OSType inComponentSignature,
+ UInt32 inOptions,
+ const char * inAssertionString,
+ const char * inExceptionString,
+ const char * inErrorString,
+ const char * inFileName,
+ long inLineNumber,
+ void * inValue,
+ ConstStr255Param inOutputMsg );
+#endif
+
+// Utilities
+
+static char * DebugNumVersionToString( uint32_t inVersion, char *inString );
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ static void DebugWinEnableConsole( void );
+#endif
+
+#if( TARGET_OS_WIN32 )
+ static TCHAR *
+ DebugWinCharToTCharString(
+ const char * inCharString,
+ size_t inCharCount,
+ TCHAR * outTCharString,
+ size_t inTCharCountMax,
+ size_t * outTCharCount );
+#endif
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+// Private Globals
+//===========================================================================================================================
+
+#if( TARGET_OS_VXWORKS )
+ // TCP States for inetstatShow.
+
+ extern char ** pTcpstates; // defined in tcpLib.c
+
+ const char * kDebugTCPStates[] =
+ {
+ "(0) TCPS_CLOSED",
+ "(1) TCPS_LISTEN",
+ "(2) TCPS_SYN_SENT",
+ "(3) TCPS_SYN_RECEIVED",
+ "(4) TCPS_ESTABLISHED",
+ "(5) TCPS_CLOSE_WAIT",
+ "(6) TCPS_FIN_WAIT_1",
+ "(7) TCPS_CLOSING",
+ "(8) TCPS_LAST_ACK",
+ "(9) TCPS_FIN_WAIT_2",
+ "(10) TCPS_TIME_WAIT",
+ };
+#endif
+
+// General
+
+static bool gDebugInitialized = false;
+static DebugOutputType gDebugOutputType = kDebugOutputTypeNone;
+static DebugLevel gDebugPrintLevelMin = kDebugLevelInfo;
+static DebugLevel gDebugPrintLevelMax = kDebugLevelMax;
+static DebugLevel gDebugBreakLevel = kDebugLevelAssert;
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+ static DebugAssertOutputHandlerUPP gDebugAssertOutputHandlerUPP = NULL;
+#endif
+
+// Custom
+
+static DebugOutputFunctionPtr gDebugCustomOutputFunction = NULL;
+static void * gDebugCustomOutputContext = NULL;
+
+// fprintf
+
+#if( DEBUG_FPRINTF_ENABLED )
+ static FILE * gDebugFPrintFFile = NULL;
+#endif
+
+// MacOSXLog
+
+#if( TARGET_OS_MAC )
+ typedef int ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... );
+
+ static DebugMacOSXLogFunctionPtr gDebugMacOSXLogFunction = NULL;
+#endif
+
+// WindowsEventLog
+
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ static HANDLE gDebugWindowsEventLogEventSource = NULL;
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == General ==
+#endif
+
+//===========================================================================================================================
+// DebugInitialize
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... )
+{
+ OSStatus err;
+ DebugOutputType type;
+ va_list args;
+
+ va_start( args, inType );
+
+#if( TARGET_OS_VXWORKS )
+ // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
+
+ if( !pTcpstates )
+ {
+ pTcpstates = (char **) kDebugTCPStates;
+ }
+#endif
+
+ // Set up DebugLib stuff (if building with Debugging.h).
+
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+ if( !gDebugAssertOutputHandlerUPP )
+ {
+ gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler );
+ check( gDebugAssertOutputHandlerUPP );
+ if( gDebugAssertOutputHandlerUPP )
+ {
+ InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP );
+ }
+ }
+#endif
+
+ // Pre-process meta-output kind to pick an appropriate output kind for the platform.
+
+ type = inType;
+ if( type == kDebugOutputTypeMetaConsole )
+ {
+ #if( TARGET_OS_MAC )
+ type = kDebugOutputTypeMacOSXLog;
+ #elif( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ #if( DEBUG_FPRINTF_ENABLED )
+ type = kDebugOutputTypeFPrintF;
+ #else
+ type = kDebugOutputTypeWindowsDebugger;
+ #endif
+ #elif( TARGET_API_MAC_OSX_KERNEL )
+ #if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+ type = kDebugOutputTypeMacOSXIOLog;
+ #elif( DEBUG_IDEBUG_ENABLED )
+ type = kDebugOutputTypeiDebug;
+ #elif( DEBUG_KPRINTF_ENABLED )
+ type = kDebugOutputTypeKPrintF;
+ #endif
+ #elif( TARGET_OS_VXWORKS )
+ #if( DEBUG_FPRINTF_ENABLED )
+ type = kDebugOutputTypeFPrintF;
+ #else
+ #error target is VxWorks, but fprintf output is disabled
+ #endif
+ #else
+ #if( DEBUG_FPRINTF_ENABLED )
+ type = kDebugOutputTypeFPrintF;
+ #endif
+ #endif
+ }
+
+ // Process output kind.
+
+ gDebugOutputType = type;
+ switch( type )
+ {
+ case kDebugOutputTypeNone:
+ err = kNoErr;
+ break;
+
+ case kDebugOutputTypeCustom:
+ gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr );
+ gDebugCustomOutputContext = va_arg( args, void * );
+ err = kNoErr;
+ break;
+
+#if( DEBUG_FPRINTF_ENABLED )
+ case kDebugOutputTypeFPrintF:
+ if( inType == kDebugOutputTypeMetaConsole )
+ {
+ err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL );
+ }
+ else
+ {
+ DebugOutputTypeFlags flags;
+ const char * filename;
+
+ flags = (DebugOutputTypeFlags) va_arg( args, unsigned int );
+ if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile )
+ {
+ filename = va_arg( args, const char * );
+ }
+ else
+ {
+ filename = NULL;
+ }
+ err = DebugFPrintFInit( flags, filename );
+ }
+ break;
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED )
+ case kDebugOutputTypeiDebug:
+ err = DebugiDebugInit();
+ break;
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+ case kDebugOutputTypeKPrintF:
+ err = kNoErr;
+ break;
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+ case kDebugOutputTypeMacOSXIOLog:
+ err = kNoErr;
+ break;
+#endif
+
+#if( TARGET_OS_MAC )
+ case kDebugOutputTypeMacOSXLog:
+ err = DebugMacOSXLogInit();
+ break;
+#endif
+
+#if( TARGET_OS_WIN32 )
+ case kDebugOutputTypeWindowsDebugger:
+ err = kNoErr;
+ break;
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ case kDebugOutputTypeWindowsEventLog:
+ {
+ const char * name;
+ HMODULE module;
+
+ name = va_arg( args, const char * );
+ module = va_arg( args, HMODULE );
+ err = DebugWindowsEventLogInit( name, module );
+ }
+ break;
+#endif
+
+ default:
+ err = kParamErr;
+ goto exit;
+ }
+ gDebugInitialized = true;
+
+exit:
+ va_end( args );
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugFinalize
+//===========================================================================================================================
+
+DEBUG_EXPORT void DebugFinalize( void )
+{
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+ check( gDebugAssertOutputHandlerUPP );
+ if( gDebugAssertOutputHandlerUPP )
+ {
+ InstallDebugAssertOutputHandler( NULL );
+ DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP );
+ gDebugAssertOutputHandlerUPP = NULL;
+ }
+#endif
+}
+
+//===========================================================================================================================
+// DebugGetProperty
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... )
+{
+ OSStatus err;
+ va_list args;
+ DebugLevel * level;
+
+ va_start( args, inTag );
+ switch( inTag )
+ {
+ case kDebugPropertyTagPrintLevelMin:
+ level = va_arg( args, DebugLevel * );
+ *level = gDebugPrintLevelMin;
+ err = kNoErr;
+ break;
+
+ case kDebugPropertyTagPrintLevelMax:
+ level = va_arg( args, DebugLevel * );
+ *level = gDebugPrintLevelMax;
+ err = kNoErr;
+ break;
+
+ case kDebugPropertyTagBreakLevel:
+ level = va_arg( args, DebugLevel * );
+ *level = gDebugBreakLevel;
+ err = kNoErr;
+ break;
+
+ default:
+ err = kUnsupportedErr;
+ break;
+ }
+ va_end( args );
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugSetProperty
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... )
+{
+ OSStatus err;
+ va_list args;
+ DebugLevel level;
+
+ va_start( args, inTag );
+ switch( inTag )
+ {
+ case kDebugPropertyTagPrintLevelMin:
+ level = va_arg( args, DebugLevel );
+ gDebugPrintLevelMin = level;
+ err = kNoErr;
+ break;
+
+ case kDebugPropertyTagPrintLevelMax:
+ level = va_arg( args, DebugLevel );
+ gDebugPrintLevelMax = level;
+ err = kNoErr;
+ break;
+
+ case kDebugPropertyTagBreakLevel:
+ level = va_arg( args, DebugLevel );
+ gDebugBreakLevel = level;
+ err = kNoErr;
+ break;
+
+ default:
+ err = kUnsupportedErr;
+ break;
+ }
+ va_end( args );
+ return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Output ==
+#endif
+
+//===========================================================================================================================
+// DebugPrintF
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... )
+{
+ va_list args;
+ size_t n;
+
+ // Skip if the level is not in the enabled range..
+
+ if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+ {
+ n = 0;
+ goto exit;
+ }
+
+ va_start( args, inFormat );
+ n = DebugPrintFVAList( inLevel, inFormat, args );
+ va_end( args );
+
+exit:
+ return( n );
+}
+
+//===========================================================================================================================
+// DebugPrintFVAList
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs )
+{
+ size_t n;
+ char buffer[ 512 ];
+
+ // Skip if the level is not in the enabled range..
+
+ if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+ {
+ n = 0;
+ goto exit;
+ }
+
+ n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs );
+ DebugPrint( inLevel, buffer, (size_t) n );
+
+exit:
+ return( n );
+}
+
+//===========================================================================================================================
+// DebugPrint
+//===========================================================================================================================
+
+static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
+{
+ OSStatus err;
+
+ // Skip if the level is not in the enabled range..
+
+ if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+ {
+ err = kRangeErr;
+ goto exit;
+ }
+
+ // Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available).
+
+ if( DebugTaskLevel() & kDebugInterruptLevelMask )
+ {
+ #if( TARGET_OS_VXWORKS )
+ logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
+ #endif
+
+ err = kExecutionStateErr;
+ goto exit;
+ }
+
+ // Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage).
+
+ if( !gDebugInitialized )
+ {
+ debug_initialize( kDebugOutputTypeMetaConsole );
+ }
+
+ // Print based on the current output type.
+
+ switch( gDebugOutputType )
+ {
+ case kDebugOutputTypeNone:
+ break;
+
+ case kDebugOutputTypeCustom:
+ if( gDebugCustomOutputFunction )
+ {
+ gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext );
+ }
+ break;
+
+#if( DEBUG_FPRINTF_ENABLED )
+ case kDebugOutputTypeFPrintF:
+ DebugFPrintFPrint( inData, inSize );
+ break;
+#endif
+
+#if( DEBUG_IDEBUG_ENABLED )
+ case kDebugOutputTypeiDebug:
+ DebugiDebugPrint( inData, inSize );
+ break;
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+ case kDebugOutputTypeKPrintF:
+ DebugKPrintFPrint( inData, inSize );
+ break;
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+ case kDebugOutputTypeMacOSXIOLog:
+ DebugMacOSXIOLogPrint( inData, inSize );
+ break;
+#endif
+
+#if( TARGET_OS_MAC )
+ case kDebugOutputTypeMacOSXLog:
+ DebugMacOSXLogPrint( inData, inSize );
+ break;
+#endif
+
+#if( TARGET_OS_WIN32 )
+ case kDebugOutputTypeWindowsDebugger:
+ DebugWindowsDebuggerPrint( inData, inSize );
+ break;
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ case kDebugOutputTypeWindowsEventLog:
+ DebugWindowsEventLogPrint( inLevel, inData, inSize );
+ break;
+#endif
+
+ default:
+ break;
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugPrintAssert
+//
+// Warning: This routine relies on several of the strings being string constants that will exist forever because the
+// underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based
+// pointer variables (e.g. local strings). The debug macros that invoke this function only use constant
+// constant strings, but if this function is invoked directly from other places, it must use constant strings.
+//===========================================================================================================================
+
+DEBUG_EXPORT void
+ DebugPrintAssert(
+ int_least32_t inErrorCode,
+ const char * inAssertString,
+ const char * inMessage,
+ const char * inFilename,
+ int_least32_t inLineNumber,
+ const char * inFunction )
+{
+ // Skip if the level is not in the enabled range..
+
+ if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) )
+ {
+ return;
+ }
+
+ if( inErrorCode != 0 )
+ {
+ DebugPrintF(
+ kDebugLevelAssert,
+ "\n"
+ "[ASSERT] error: %ld (%m)\n"
+ "[ASSERT] where: \"%s\", line %ld, \"%s\"\n"
+ "\n",
+ inErrorCode, inErrorCode,
+ inFilename ? inFilename : "",
+ inLineNumber,
+ inFunction ? inFunction : "" );
+ }
+ else
+ {
+ DebugPrintF(
+ kDebugLevelAssert,
+ "\n"
+ "[ASSERT] assert: \"%s\" %s\n"
+ "[ASSERT] where: \"%s\", line %ld, \"%s\"\n"
+ "\n",
+ inAssertString ? inAssertString : "",
+ inMessage ? inMessage : "",
+ inFilename ? inFilename : "",
+ inLineNumber,
+ inFunction ? inFunction : "" );
+ }
+
+ // Break into the debugger if enabled.
+
+ #if( TARGET_OS_WIN32 )
+ if( gDebugBreakLevel <= kDebugLevelAssert )
+ {
+ if( IsDebuggerPresent() )
+ {
+ DebugBreak();
+ }
+ }
+ #endif
+}
+
+#if 0
+#pragma mark -
+#endif
+
+#if( DEBUG_FPRINTF_ENABLED )
+//===========================================================================================================================
+// DebugFPrintFInit
+//===========================================================================================================================
+
+static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename )
+{
+ OSStatus err;
+ DebugOutputTypeFlags typeFlags;
+
+ typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask;
+ if( typeFlags == kDebugOutputTypeFlagsStdOut )
+ {
+ #if( TARGET_OS_WIN32 )
+ DebugWinEnableConsole();
+ #endif
+
+ gDebugFPrintFFile = stdout;
+ }
+ else if( typeFlags == kDebugOutputTypeFlagsStdErr )
+ {
+ #if( TARGET_OS_WIN32 )
+ DebugWinEnableConsole();
+ #endif
+
+ gDebugFPrintFFile = stdout;
+ }
+ else if( typeFlags == kDebugOutputTypeFlagsFile )
+ {
+ require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr );
+
+ gDebugFPrintFFile = fopen( inFilename, "a" );
+ require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr );
+ }
+ else
+ {
+ err = kParamErr;
+ goto exit;
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugFPrintFPrint
+//===========================================================================================================================
+
+static void DebugFPrintFPrint( char *inData, size_t inSize )
+{
+ char * p;
+ char * q;
+
+ // Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform.
+
+ p = inData;
+ q = p + inSize;
+ while( p < q )
+ {
+ if( *p == '\r' )
+ {
+ *p = '\n';
+ }
+ ++p;
+ }
+
+ // Write the data and flush.
+
+ if( gDebugFPrintFFile )
+ {
+ fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData );
+ fflush( gDebugFPrintFFile );
+ }
+}
+#endif // DEBUG_FPRINTF_ENABLED
+
+#if( DEBUG_IDEBUG_ENABLED )
+//===========================================================================================================================
+// DebugiDebugInit
+//===========================================================================================================================
+
+static OSStatus DebugiDebugInit( void )
+{
+ OSStatus err;
+
+ #if( TARGET_API_MAC_OSX_KERNEL )
+
+ extern uint32_t * _giDebugReserved1;
+
+ // Emulate the iDebugSetOutputType macro in iDebugServices.h.
+ // Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext.
+
+ if( !_giDebugReserved1 )
+ {
+ _giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) );
+ require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr );
+ }
+ *_giDebugReserved1 = 0x00010000U;
+ err = kNoErr;
+exit:
+ #else
+
+ __private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType );
+
+ iDebugSetOutputTypeInternal( 0x00010000U );
+ err = kNoErr;
+
+ #endif
+
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugiDebugPrint
+//===========================================================================================================================
+
+static void DebugiDebugPrint( char *inData, size_t inSize )
+{
+ #if( TARGET_API_MAC_OSX_KERNEL )
+
+ // Locally declared here so we do not need to include iDebugKext.h.
+ // Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the
+ // KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present).
+ // _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present.
+
+ typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
+
+ extern iDebugLogFunctionPtr _giDebugLogInternal;
+
+ if( _giDebugLogInternal )
+ {
+ _giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
+ }
+
+ #else
+
+ __private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
+
+ iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
+
+ #endif
+}
+#endif
+
+#if( DEBUG_KPRINTF_ENABLED )
+//===========================================================================================================================
+// DebugKPrintFPrint
+//===========================================================================================================================
+
+static void DebugKPrintFPrint( char *inData, size_t inSize )
+{
+ extern void kprintf( const char *inFormat, ... );
+
+ kprintf( "%.*s", (int) inSize, inData );
+}
+#endif
+
+#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+//===========================================================================================================================
+// DebugMacOSXIOLogPrint
+//===========================================================================================================================
+
+static void DebugMacOSXIOLogPrint( char *inData, size_t inSize )
+{
+ extern void IOLog( const char *inFormat, ... );
+
+ IOLog( "%.*s", (int) inSize, inData );
+}
+#endif
+
+#if( TARGET_OS_MAC )
+//===========================================================================================================================
+// DebugMacOSXLogInit
+//===========================================================================================================================
+
+static OSStatus DebugMacOSXLogInit( void )
+{
+ OSStatus err;
+ CFStringRef path;
+ CFURLRef url;
+ CFBundleRef bundle;
+ CFStringRef functionName;
+ void * functionPtr;
+
+ bundle = NULL;
+
+ // Create a bundle reference for System.framework.
+
+ path = CFSTR( "/System/Library/Frameworks/System.framework" );
+ url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true );
+ require_action_quiet( url, exit, err = memFullErr );
+
+ bundle = CFBundleCreate( NULL, url );
+ CFRelease( url );
+ require_action_quiet( bundle, exit, err = memFullErr );
+
+ // Get a ptr to the system's "printf" function from System.framework.
+
+ functionName = CFSTR( "printf" );
+ functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName );
+ require_action_quiet( functionPtr, exit, err = memFullErr );
+
+ // Success! Note: The bundle cannot be released because it would invalidate the function ptr.
+
+ gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr;
+ bundle = NULL;
+ err = noErr;
+
+exit:
+ if( bundle )
+ {
+ CFRelease( bundle );
+ }
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugMacOSXLogPrint
+//===========================================================================================================================
+
+static void DebugMacOSXLogPrint( char *inData, size_t inSize )
+{
+ if( gDebugMacOSXLogFunction )
+ {
+ gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData );
+ }
+}
+#endif
+
+#if( TARGET_OS_WIN32 )
+//===========================================================================================================================
+// DebugWindowsDebuggerPrint
+//===========================================================================================================================
+
+void DebugWindowsDebuggerPrint( char *inData, size_t inSize )
+{
+ TCHAR buffer[ 512 ];
+ const char * src;
+ const char * end;
+ TCHAR * dst;
+ char c;
+
+ // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
+ // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
+
+ src = inData;
+ if( inSize >= sizeof_array( buffer ) )
+ {
+ inSize = sizeof_array( buffer ) - 1;
+ }
+ end = src + inSize;
+ dst = buffer;
+ while( src < end )
+ {
+ c = *src++;
+ if( c == '\r' )
+ {
+ c = '\n';
+ }
+ *dst++ = (TCHAR) c;
+ }
+ *dst = 0;
+
+ // Print out the string to the debugger.
+
+ OutputDebugString( buffer );
+}
+#endif
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+// DebugWindowsEventLogInit
+//===========================================================================================================================
+
+static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule )
+{
+ OSStatus err;
+ HKEY key;
+ TCHAR name[ 128 ];
+ const char * src;
+ TCHAR path[ MAX_PATH ];
+ size_t size;
+ DWORD typesSupported;
+ DWORD n;
+
+ key = NULL;
+
+ // Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds.
+
+ if( !inName || ( *inName == '\0' ) )
+ {
+ inName = "DefaultApp";
+ }
+ DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL );
+
+ // Build the path string using the fixed registry path and app name.
+
+ src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
+ DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size );
+ DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL );
+
+ // Add/Open the source name as a sub-key under the Application key in the EventLog registry key.
+
+ err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL );
+ require_noerr_quiet( err, exit );
+
+ // Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator.
+
+ n = GetModuleFileName( inModule, path, sizeof_array( path ) );
+ err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr );
+ require_noerr_quiet( err, exit );
+ n += 1;
+ n *= sizeof( TCHAR );
+
+ err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
+ require_noerr_quiet( err, exit );
+
+ // Set the supported event types in the TypesSupported subkey.
+
+ typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE |
+ EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
+ err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
+ require_noerr_quiet( err, exit );
+
+ // Set up the event source.
+
+ gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name );
+ err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr );
+ require_noerr_quiet( err, exit );
+
+exit:
+ if( key )
+ {
+ RegCloseKey( key );
+ }
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugWindowsEventLogPrint
+//===========================================================================================================================
+
+static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize )
+{
+ WORD type;
+ TCHAR buffer[ 512 ];
+ const char * src;
+ const char * end;
+ TCHAR * dst;
+ char c;
+ const TCHAR * array[ 1 ];
+
+ // Map the debug level to a Windows EventLog type.
+
+ if( inLevel <= kDebugLevelNotice )
+ {
+ type = EVENTLOG_INFORMATION_TYPE;
+ }
+ else if( inLevel <= kDebugLevelWarning )
+ {
+ type = EVENTLOG_WARNING_TYPE;
+ }
+ else
+ {
+ type = EVENTLOG_ERROR_TYPE;
+ }
+
+ // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
+ // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
+
+ src = inData;
+ if( inSize >= sizeof_array( buffer ) )
+ {
+ inSize = sizeof_array( buffer ) - 1;
+ }
+ end = src + inSize;
+ dst = buffer;
+ while( src < end )
+ {
+ c = *src++;
+ if( c == '\r' )
+ {
+ c = '\n';
+ }
+ *dst++ = (TCHAR) c;
+ }
+ *dst = 0;
+
+ // Add the the string to the event log.
+
+ array[ 0 ] = buffer;
+ if( gDebugWindowsEventLogEventSource )
+ {
+ ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL );
+ }
+}
+#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
+
+#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+//===========================================================================================================================
+// DebugAssertOutputHandler
+//===========================================================================================================================
+
+static pascal void
+ DebugAssertOutputHandler(
+ OSType inComponentSignature,
+ UInt32 inOptions,
+ const char * inAssertString,
+ const char * inExceptionString,
+ const char * inErrorString,
+ const char * inFileName,
+ long inLineNumber,
+ void * inValue,
+ ConstStr255Param inOutputMsg )
+{
+ DEBUG_UNUSED( inComponentSignature );
+ DEBUG_UNUSED( inOptions );
+ DEBUG_UNUSED( inExceptionString );
+ DEBUG_UNUSED( inValue );
+ DEBUG_UNUSED( inOutputMsg );
+
+ DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" );
+}
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == Utilities ==
+#endif
+
+//===========================================================================================================================
+// DebugSNPrintF
+//
+// Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes:
+//
+// Changed names to avoid name collisions with the mDNS versions.
+// Changed types to standard C types since mDNSEmbeddedAPI.h may not be available.
+// Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h.
+// Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
+// Added %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
+// Added %.8a - FIbre Channel address. Arg=ptr to address.
+// Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
+// Added %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
+// Added %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
+// Added %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+// Added %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+// Added %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc.
+// Added %S - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr.
+// Added %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
+// Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
+// Added %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...)
+ {
+ size_t length;
+
+ va_list ptr;
+ va_start(ptr,fmt);
+ length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr);
+ va_end(ptr);
+
+ return(length);
+ }
+
+//===========================================================================================================================
+// DebugSNPrintFVAList - va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg)
+ {
+ static const struct DebugSNPrintF_format
+ {
+ unsigned leftJustify : 1;
+ unsigned forceSign : 1;
+ unsigned zeroPad : 1;
+ unsigned havePrecision : 1;
+ unsigned hSize : 1;
+ char lSize;
+ char altForm;
+ char sign; // +, - or space
+ unsigned int fieldWidth;
+ unsigned int precision;
+ } DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ size_t nwritten = 0;
+ int c;
+ if (buflen == 0) return(0);
+ buflen--; // Pre-reserve one space in the buffer for the terminating nul
+ if (buflen == 0) goto exit;
+
+ for (c = *fmt; c != 0; c = *++fmt)
+ {
+ if (c != '%')
+ {
+ *sbuffer++ = (char)c;
+ if (++nwritten >= buflen) goto exit;
+ }
+ else
+ {
+ size_t i=0, j;
+ // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
+ // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
+ // The size needs to be enough for a 256-byte domain name plus some error text.
+ #define mDNS_VACB_Size 300
+ char mDNS_VACB[mDNS_VACB_Size];
+ #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
+ #define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s))
+ char *s = mDNS_VACB_Lim;
+ const char *digits = "0123456789ABCDEF";
+ struct DebugSNPrintF_format F = DebugSNPrintF_format_default;
+
+ for(;;) // decode flags
+ {
+ c = *++fmt;
+ if (c == '-') F.leftJustify = 1;
+ else if (c == '+') F.forceSign = 1;
+ else if (c == ' ') F.sign = ' ';
+ else if (c == '#') F.altForm++;
+ else if (c == '0') F.zeroPad = 1;
+ else break;
+ }
+
+ if (c == '*') // decode field width
+ {
+ int f = va_arg(arg, int);
+ if (f < 0) { f = -f; F.leftJustify = 1; }
+ F.fieldWidth = (unsigned int)f;
+ c = *++fmt;
+ }
+ else
+ {
+ for (; c >= '0' && c <= '9'; c = *++fmt)
+ F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
+ }
+
+ if (c == '.') // decode precision
+ {
+ if ((c = *++fmt) == '*')
+ { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
+ else for (; c >= '0' && c <= '9'; c = *++fmt)
+ F.precision = (10 * F.precision) + (c - '0');
+ F.havePrecision = 1;
+ }
+
+ if (F.leftJustify) F.zeroPad = 0;
+
+ conv:
+ switch (c) // perform appropriate conversion
+ {
+ #if TYPE_LONGLONG_NATIVE
+ unsigned_long_long_compat n;
+ unsigned_long_long_compat base;
+ #else
+ unsigned long n;
+ unsigned long base;
+ #endif
+ case 'h' : F.hSize = 1; c = *++fmt; goto conv;
+ case 'l' : // fall through
+ case 'L' : F.lSize++; c = *++fmt; goto conv;
+ case 'd' :
+ case 'i' : base = 10;
+ goto canBeSigned;
+ case 'u' : base = 10;
+ goto notSigned;
+ case 'o' : base = 8;
+ goto notSigned;
+ case 'b' : base = 2;
+ goto notSigned;
+ case 'p' : n = va_arg(arg, uintptr_t);
+ F.havePrecision = 1;
+ F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16;
+ F.sign = 0;
+ base = 16;
+ c = 'x';
+ goto number;
+ case 'x' : digits = "0123456789abcdef";
+ case 'X' : base = 16;
+ goto notSigned;
+ canBeSigned:
+ #if TYPE_LONGLONG_NATIVE
+ if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long);
+ else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat);
+ else n = (unsigned_long_long_compat)va_arg(arg, int);
+ #else
+ if (F.lSize == 1) n = (unsigned long)va_arg(arg, long);
+ else if (F.lSize == 2) goto exit;
+ else n = (unsigned long)va_arg(arg, int);
+ #endif
+ if (F.hSize) n = (short) n;
+ #if TYPE_LONGLONG_NATIVE
+ if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; }
+ #else
+ if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
+ #endif
+ else if (F.forceSign) F.sign = '+';
+ goto number;
+
+ notSigned: if (F.lSize == 1) n = va_arg(arg, unsigned long);
+ else if (F.lSize == 2)
+ {
+ #if TYPE_LONGLONG_NATIVE
+ n = va_arg(arg, unsigned_long_long_compat);
+ #else
+ goto exit;
+ #endif
+ }
+ else n = va_arg(arg, unsigned int);
+ if (F.hSize) n = (unsigned short) n;
+ F.sign = 0;
+ goto number;
+
+ number: if (!F.havePrecision)
+ {
+ if (F.zeroPad)
+ {
+ F.precision = F.fieldWidth;
+ if (F.altForm) F.precision -= 2;
+ if (F.sign) --F.precision;
+ }
+ if (F.precision < 1) F.precision = 1;
+ }
+ if (F.precision > mDNS_VACB_Size - 1)
+ F.precision = mDNS_VACB_Size - 1;
+ for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]);
+ for (; i < F.precision; i++) *--s = '0';
+ if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
+ if (F.sign) { *--s = F.sign; i++; }
+ break;
+
+ case 'a' : {
+ unsigned char *a = va_arg(arg, unsigned char *);
+ char pre[4] = "";
+ char post[32] = "";
+ if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ else
+ {
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ if (F.altForm == 1)
+ {
+ #if(defined(MDNS_DEBUGMSGS))
+ mDNSAddr *ip = (mDNSAddr*)a;
+ switch (ip->type)
+ {
+ case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break;
+ case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
+ default: F.precision = 0; break;
+ }
+ #else
+ F.precision = 0; // mDNSEmbeddedAPI.h not included so no mDNSAddr support
+ #endif
+ }
+ else if (F.altForm == 2)
+ {
+ #ifdef AF_INET
+ const struct sockaddr *sa;
+ unsigned char *port;
+ sa = (const struct sockaddr*)a;
+ switch (sa->sa_family)
+ {
+ case AF_INET: F.precision = 4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr;
+ port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port;
+ DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break;
+ #ifdef AF_INET6
+ case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr;
+ pre[0] = '['; pre[1] = '\0';
+ port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port;
+ DebugSNPrintF(post, sizeof(post), "%%%d]:%d",
+ (int)((const struct sockaddr_in6 *)sa)->sin6_scope_id,
+ (port[0] << 8) | port[1]); break;
+ #endif
+ default: F.precision = 0; break;
+ }
+ #else
+ F.precision = 0; // socket interfaces not included so no sockaddr support
+ #endif
+ }
+ switch (F.precision)
+ {
+ case 4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s",
+ a[0], a[1], a[2], a[3], post); break;
+ case 6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
+ a[0], a[1], a[2], a[3], a[4], a[5]); break;
+ case 8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
+ a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
+ case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB),
+ "%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s",
+ pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8],
+ a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break;
+ default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
+ "(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break;
+ }
+ }
+ }
+ break;
+
+ case 'U' : {
+ unsigned char *a = va_arg(arg, unsigned char *);
+ if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ else
+ {
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ *((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]),
+ a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break;
+ }
+ }
+ break;
+
+ case 'c' : *--s = (char)va_arg(arg, int); i = 1; break;
+
+ case 'C' : if (F.lSize) n = va_arg(arg, unsigned long);
+ else n = va_arg(arg, unsigned int);
+ if (F.hSize) n = (unsigned short) n;
+ c = (int)( n & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+ c = (int)((n >> 8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+ c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+ c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+ i = 4;
+ break;
+
+ case 's' : s = va_arg(arg, char *);
+ if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ else switch (F.altForm)
+ {
+ case 0: i=0;
+ if (F.havePrecision) // C string
+ {
+ while((i < F.precision) && s[i]) i++;
+ // Make sure we don't truncate in the middle of a UTF-8 character.
+ // If the last character is part of a multi-byte UTF-8 character, back up to the start of it.
+ j=0;
+ while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break; }
+ // If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back.
+ if((j > 1) && (j <= 6))
+ {
+ int test = (0xFF << (8-j)) & 0xFF;
+ int mask = test | (1 << ((8-j)-1));
+ if((c & mask) == test) i += j;
+ }
+ }
+ else
+ while(s[i]) i++;
+ break;
+ case 1: i = (unsigned char) *s++; break; // Pascal string
+ case 2: { // DNS label-sequence name
+ unsigned char *a = (unsigned char *)s;
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ if (*a == 0) *s++ = '.'; // Special case for root DNS name
+ while (*a)
+ {
+ if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
+ if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
+ s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a);
+ a += 1 + *a;
+ }
+ i = (size_t)(s - mDNS_VACB);
+ s = mDNS_VACB; // Reset s back to the start of the buffer
+ break;
+ }
+ }
+ if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character
+ { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+ break;
+
+ case 'S': { // UTF-16 string
+ unsigned char *a = va_arg(arg, unsigned char *);
+ uint16_t *u = (uint16_t*)a;
+ if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ if ((!F.havePrecision || F.precision))
+ {
+ if ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; } // Big Endian
+ else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; } // Little Endian
+ }
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ switch (F.altForm)
+ {
+ case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Host Endian
+ { c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; }
+ break;
+ case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Big Endian
+ { c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
+ break;
+ case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Little Endian
+ { c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
+ break;
+ }
+ }
+ s = mDNS_VACB; // Reset s back to the start of the buffer
+ break;
+
+ #if TARGET_OS_MAC
+ case '@': { // Cocoa/CoreFoundation object
+ CFTypeRef cfObj;
+ CFStringRef cfStr;
+ cfObj = (CFTypeRef) va_arg(arg, void *);
+ cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj);
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ if (cfStr)
+ {
+ CFRange range;
+ CFIndex m;
+ range = CFRangeMake(0, CFStringGetLength(cfStr));
+ m = 0;
+ CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m);
+ CFRelease(cfStr);
+ i = (size_t) m;
+ }
+ else
+ {
+ i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" );
+ }
+ }
+ if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character
+ { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+ break;
+ #endif
+
+ case 'm' : { // Error Message
+ long err;
+ if (F.lSize) err = va_arg(arg, long);
+ else err = va_arg(arg, int);
+ if (F.hSize) err = (short)err;
+ DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB));
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ for(i=0;s[i];i++) {}
+ }
+ break;
+
+ case 'H' : { // Hex Dump
+ void *a = va_arg(arg, void *);
+ size_t size = (size_t)va_arg(arg, int);
+ size_t max = (size_t)va_arg(arg, int);
+ DebugFlags flags =
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
+ kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator |
+ kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount;
+ if (F.altForm == 0) flags |= kDebugFlagsNoASCII;
+ size = (max < size) ? max : size;
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB));
+ }
+ break;
+
+ case 'v' : { // Version
+ uint32_t version;
+ version = va_arg(arg, unsigned int);
+ DebugNumVersionToString(version, mDNS_VACB);
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ for(i=0;s[i];i++) {}
+ }
+ break;
+
+ case 'n' : s = va_arg(arg, char *);
+ if (F.hSize) * (short *) s = (short)nwritten;
+ else if (F.lSize) * (long *) s = (long)nwritten;
+ else * (int *) s = (int)nwritten;
+ continue;
+
+ default: s = mDNS_VACB;
+ i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
+
+ case '%' : *sbuffer++ = (char)c;
+ if (++nwritten >= buflen) goto exit;
+ break;
+ }
+
+ if (i < F.fieldWidth && !F.leftJustify) // Pad on the left
+ do {
+ *sbuffer++ = ' ';
+ if (++nwritten >= buflen) goto exit;
+ } while (i < --F.fieldWidth);
+
+ if (i > buflen - nwritten) // Make sure we don't truncate in the middle of a UTF-8 character
+ { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
+ for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result
+ nwritten += i;
+ if (nwritten >= buflen) goto exit;
+
+ for (; i < F.fieldWidth; i++) // Pad on the right
+ {
+ *sbuffer++ = ' ';
+ if (++nwritten >= buflen) goto exit;
+ }
+ }
+ }
+ exit:
+ *sbuffer++ = 0;
+ return(nwritten);
+ }
+
+//===========================================================================================================================
+// DebugGetErrorString
+//===========================================================================================================================
+
+DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize )
+{
+ const char * s;
+ char * dst;
+ char * end;
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ char buffer[ 256 ];
+#endif
+
+ switch( inErrorCode )
+ {
+ #define CaseErrorString( X, STR ) case X: s = STR; break
+ #define CaseErrorStringify( X ) case X: s = # X; break
+ #define CaseErrorStringifyHardCode( VALUE, X ) case VALUE: s = # X; break
+
+ // General Errors
+
+ CaseErrorString( 0, "no error" );
+ CaseErrorString( 1, "in-progress/waiting" );
+ CaseErrorString( -1, "catch-all unknown error" );
+
+ // ACP Errors
+
+ CaseErrorStringifyHardCode( -2, kACPBadRequestErr );
+ CaseErrorStringifyHardCode( -3, kACPNoMemoryErr );
+ CaseErrorStringifyHardCode( -4, kACPBadParamErr );
+ CaseErrorStringifyHardCode( -5, kACPNotFoundErr );
+ CaseErrorStringifyHardCode( -6, kACPBadChecksumErr );
+ CaseErrorStringifyHardCode( -7, kACPCommandNotHandledErr );
+ CaseErrorStringifyHardCode( -8, kACPNetworkErr );
+ CaseErrorStringifyHardCode( -9, kACPDuplicateCommandHandlerErr );
+ CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr );
+ CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr );
+ CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr );
+ CaseErrorStringifyHardCode( -13, kACPNoResourcesErr );
+ CaseErrorStringifyHardCode( -14, kACPBadOptionErr );
+ CaseErrorStringifyHardCode( -15, kACPBadSizeErr );
+ CaseErrorStringifyHardCode( -16, kACPBadPasswordErr );
+ CaseErrorStringifyHardCode( -17, kACPNotInitializedErr );
+ CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr );
+ CaseErrorStringifyHardCode( -19, kACPBadVersionErr );
+ CaseErrorStringifyHardCode( -20, kACPBadSignatureErr );
+ CaseErrorStringifyHardCode( -21, kACPBadIndexErr );
+ CaseErrorStringifyHardCode( -22, kACPUnsupportedErr );
+ CaseErrorStringifyHardCode( -23, kACPInUseErr );
+ CaseErrorStringifyHardCode( -24, kACPParamCountErr );
+ CaseErrorStringifyHardCode( -25, kACPIDErr );
+ CaseErrorStringifyHardCode( -26, kACPFormatErr );
+ CaseErrorStringifyHardCode( -27, kACPUnknownUserErr );
+ CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr );
+ CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr );
+
+ // Common Services Errors
+
+ CaseErrorStringify( kUnknownErr );
+ CaseErrorStringify( kOptionErr );
+ CaseErrorStringify( kSelectorErr );
+ CaseErrorStringify( kExecutionStateErr );
+ CaseErrorStringify( kPathErr );
+ CaseErrorStringify( kParamErr );
+ CaseErrorStringify( kParamCountErr );
+ CaseErrorStringify( kCommandErr );
+ CaseErrorStringify( kIDErr );
+ CaseErrorStringify( kStateErr );
+ CaseErrorStringify( kRangeErr );
+ CaseErrorStringify( kRequestErr );
+ CaseErrorStringify( kResponseErr );
+ CaseErrorStringify( kChecksumErr );
+ CaseErrorStringify( kNotHandledErr );
+ CaseErrorStringify( kVersionErr );
+ CaseErrorStringify( kSignatureErr );
+ CaseErrorStringify( kFormatErr );
+ CaseErrorStringify( kNotInitializedErr );
+ CaseErrorStringify( kAlreadyInitializedErr );
+ CaseErrorStringify( kNotInUseErr );
+ CaseErrorStringify( kInUseErr );
+ CaseErrorStringify( kTimeoutErr );
+ CaseErrorStringify( kCanceledErr );
+ CaseErrorStringify( kAlreadyCanceledErr );
+ CaseErrorStringify( kCannotCancelErr );
+ CaseErrorStringify( kDeletedErr );
+ CaseErrorStringify( kNotFoundErr );
+ CaseErrorStringify( kNoMemoryErr );
+ CaseErrorStringify( kNoResourcesErr );
+ CaseErrorStringify( kDuplicateErr );
+ CaseErrorStringify( kImmutableErr );
+ CaseErrorStringify( kUnsupportedDataErr );
+ CaseErrorStringify( kIntegrityErr );
+ CaseErrorStringify( kIncompatibleErr );
+ CaseErrorStringify( kUnsupportedErr );
+ CaseErrorStringify( kUnexpectedErr );
+ CaseErrorStringify( kValueErr );
+ CaseErrorStringify( kNotReadableErr );
+ CaseErrorStringify( kNotWritableErr );
+ CaseErrorStringify( kBadReferenceErr );
+ CaseErrorStringify( kFlagErr );
+ CaseErrorStringify( kMalformedErr );
+ CaseErrorStringify( kSizeErr );
+ CaseErrorStringify( kNameErr );
+ CaseErrorStringify( kNotReadyErr );
+ CaseErrorStringify( kReadErr );
+ CaseErrorStringify( kWriteErr );
+ CaseErrorStringify( kMismatchErr );
+ CaseErrorStringify( kDateErr );
+ CaseErrorStringify( kUnderrunErr );
+ CaseErrorStringify( kOverrunErr );
+ CaseErrorStringify( kEndingErr );
+ CaseErrorStringify( kConnectionErr );
+ CaseErrorStringify( kAuthenticationErr );
+ CaseErrorStringify( kOpenErr );
+ CaseErrorStringify( kTypeErr );
+ CaseErrorStringify( kSkipErr );
+ CaseErrorStringify( kNoAckErr );
+ CaseErrorStringify( kCollisionErr );
+ CaseErrorStringify( kBackoffErr );
+ CaseErrorStringify( kNoAddressAckErr );
+ CaseErrorStringify( kBusyErr );
+ CaseErrorStringify( kNoSpaceErr );
+
+ // mDNS/DNS-SD Errors
+
+ CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr );
+ CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr );
+ CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr );
+ CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr );
+ CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr );
+ CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr );
+ CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr );
+ CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr );
+ CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr );
+ CaseErrorStringifyHardCode( -65546, mStatus_NoCache );
+ CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered );
+ CaseErrorStringifyHardCode( -65548, mStatus_NameConflict );
+ CaseErrorStringifyHardCode( -65549, mStatus_Invalid );
+ CaseErrorStringifyHardCode( -65550, mStatus_GrowCache );
+ CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr );
+ CaseErrorStringifyHardCode( -65552, mStatus_Incompatible );
+ CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged );
+ CaseErrorStringifyHardCode( -65792, mStatus_MemFree );
+
+ // RSP Errors
+
+ CaseErrorStringifyHardCode( -400000, kRSPUnknownErr );
+ CaseErrorStringifyHardCode( -400050, kRSPParamErr );
+ CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr );
+ CaseErrorStringifyHardCode( -405246, kRSPRangeErr );
+ CaseErrorStringifyHardCode( -409057, kRSPSizeErr );
+ CaseErrorStringifyHardCode( -400200, kRSPHardwareErr );
+ CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr );
+ CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr );
+ CaseErrorStringifyHardCode( -402419, kRSPIDErr );
+ CaseErrorStringifyHardCode( -403165, kRSPFlagErr );
+ CaseErrorString( -200000, "kRSPControllerStatusBase - 0x50" );
+ CaseErrorString( -200080, "kRSPCommandSucceededErr - 0x50" );
+ CaseErrorString( -200001, "kRSPCommandFailedErr - 0x01" );
+ CaseErrorString( -200051, "kRSPChecksumErr - 0x33" );
+ CaseErrorString( -200132, "kRSPCommandTimeoutErr - 0x84" );
+ CaseErrorString( -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" );
+ CaseErrorString( -200128, "kRSPCanceledErr - 0x02 Async" );
+
+ // XML Errors
+
+ CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr );
+ CaseErrorStringifyHardCode( -100050, kXMLParamErr );
+ CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr );
+ CaseErrorStringifyHardCode( -100206, kXMLFormatErr );
+ CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr );
+ CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr );
+ CaseErrorStringifyHardCode( -101726, kXMLKeyErr );
+ CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr );
+ CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr );
+ CaseErrorStringifyHardCode( -103026, kXMLParseErr );
+ CaseErrorStringifyHardCode( -103159, kXMLBadDataErr );
+ CaseErrorStringifyHardCode( -103170, kXMLBadNameErr );
+ CaseErrorStringifyHardCode( -105246, kXMLRangeErr );
+ CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr );
+ CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr );
+ CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr );
+ CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr );
+ CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr );
+ CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr );
+ CaseErrorStringifyHardCode( -102015, kXMLDateErr );
+
+ #if( __MACH__ )
+
+ // Mach Errors
+
+ CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE );
+ CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE );
+ CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL );
+ CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL );
+ CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS );
+ CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA );
+ CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST );
+ CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT );
+ CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED );
+ CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL );
+ CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY );
+ CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT );
+ CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY );
+ CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY );
+ CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER );
+ CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE );
+ CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE );
+ CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER );
+ CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER );
+ CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE );
+ CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS );
+ CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME );
+ CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT );
+ CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE );
+ CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED );
+ CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED );
+ CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY );
+ CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA );
+ CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED );
+ CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET );
+ CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR );
+ CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR );
+ CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE );
+ CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL );
+ CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER );
+ CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED );
+
+ // Mach OSReturn Errors
+
+ CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError );
+ CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal );
+ CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances );
+ CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit );
+ CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData );
+ CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts );
+ CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet );
+ CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet );
+ CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper );
+ CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper );
+ CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass );
+
+ // IOKit Errors
+
+ CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError );
+ CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory );
+ CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources );
+ CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError );
+ CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice );
+ CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged );
+ CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument );
+ CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead );
+ CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite );
+ CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess );
+ CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID );
+ CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported );
+ CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError );
+ CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError );
+ CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError );
+ CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock );
+ CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen );
+ CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable );
+ CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable );
+ CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned );
+ CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia );
+ CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen );
+ CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError );
+ CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError );
+ CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy );
+ CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout );
+ CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline );
+ CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady );
+ CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached );
+ CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels );
+ CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace );
+ CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists );
+ CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire );
+ CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt );
+ CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames );
+ CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge );
+ CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted );
+ CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower );
+ CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia );
+ CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia );
+ CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode );
+ CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun );
+ CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun );
+ CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError );
+ CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion );
+ CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted );
+ CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth );
+ CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding );
+ CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld );
+ CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew );
+ CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound );
+ CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid );
+
+ // IOKit FireWire Errors
+
+ CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase );
+ CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset );
+ CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry );
+ CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending );
+ CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken );
+ CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid );
+ CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered );
+ CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers );
+ CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive );
+ CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker );
+ CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels );
+ CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable );
+ CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus );
+ CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs );
+ CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage );
+ CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower );
+ CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels );
+ CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram );
+ CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening );
+ CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept );
+ CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose );
+ CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged );
+ CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged );
+
+ // IOKit USB Errors
+
+ CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr );
+ CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr );
+ CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr );
+ CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr );
+ CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr );
+ CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound );
+ CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound );
+ CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout );
+ CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned );
+ CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled );
+ CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound );
+ CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated );
+ CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated );
+ CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError );
+ CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr );
+ CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err );
+ CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err );
+ CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr );
+ CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr );
+ CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err );
+ CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err );
+ CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr );
+ CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr );
+ CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr );
+ CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr );
+ CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr );
+
+ #endif // __MACH__
+
+ // Other Errors
+
+ default:
+ s = NULL;
+ #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ if( inBuffer && ( inBufferSize > 0 ) )
+ {
+ DWORD n;
+
+ n = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) inErrorCode,
+ MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), buffer, sizeof( buffer ), NULL );
+ if( n > 0 )
+ {
+ // Remove any trailing CR's or LF's since some messages have them.
+
+ while( ( n > 0 ) && isspace( ( (unsigned char *) buffer )[ n - 1 ] ) )
+ {
+ buffer[ --n ] = '\0';
+ }
+ s = buffer;
+ }
+ }
+ #endif
+
+ if( !s )
+ {
+ #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
+ s = strerror( inErrorCode );
+ #endif
+ if( !s )
+ {
+ s = "<unknown error code>";
+ }
+ }
+ break;
+ }
+
+ // Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string.
+
+ if( inBuffer && ( inBufferSize > 0 ) )
+ {
+ dst = inBuffer;
+ end = dst + ( inBufferSize - 1 );
+ while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) )
+ {
+ *dst++ = *s++;
+ }
+ *dst = '\0';
+ s = inBuffer;
+ }
+ return( s );
+}
+
+//===========================================================================================================================
+// DebugHexDump
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t
+ DebugHexDump(
+ DebugLevel inLevel,
+ int inIndent,
+ const char * inLabel,
+ size_t inLabelSize,
+ int inLabelMinWidth,
+ const char * inType,
+ size_t inTypeSize,
+ const void * inDataStart,
+ const void * inData,
+ size_t inDataSize,
+ DebugFlags inFlags,
+ char * outBuffer,
+ size_t inBufferSize )
+{
+ static const char kHexChars[] = "0123456789ABCDEF";
+ const uint8_t * start;
+ const uint8_t * src;
+ char * dst;
+ char * end;
+ size_t n;
+ int offset;
+ int width;
+ const char * newline;
+ char separator[ 8 ];
+ char * s;
+
+ DEBUG_UNUSED( inType );
+ DEBUG_UNUSED( inTypeSize );
+
+ // Set up the function-wide variables.
+
+ if( inLabelSize == kSizeCString )
+ {
+ inLabelSize = strlen( inLabel );
+ }
+ start = (const uint8_t *) inData;
+ src = start;
+ dst = outBuffer;
+ end = dst + inBufferSize;
+ offset = (int)( (intptr_t) inData - (intptr_t) inDataStart );
+ width = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth;
+ newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n";
+
+ // Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines.
+
+ s = separator;
+ if( inFlags & kDebugFlagsNoNewLine )
+ {
+ if( inFlags & kDebugFlags8BitSeparator )
+ {
+ *s++ = ' ';
+ }
+ if( inFlags & kDebugFlags16BitSeparator )
+ {
+ *s++ = ' ';
+ }
+ if( !( inFlags & kDebugFlagsNo32BitSeparator ) )
+ {
+ *s++ = ' ';
+ }
+ check( ( (size_t)( s - separator ) ) < sizeof( separator ) );
+ }
+ *s = '\0';
+
+ for( ;; )
+ {
+ char prefixString[ 32 ];
+ char hexString[ 64 ];
+ char asciiString[ 32 ];
+ char byteCountString[ 32 ];
+ int c;
+ size_t chunkSize;
+ size_t i;
+
+ // If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit.
+
+ if( inDataSize == 0 )
+ {
+ if( inLabel && ( inLabelSize > 0 ) )
+ {
+ width = 0;
+ if( !( inFlags & kDebugFlagsNoAddress ) )
+ {
+ width += 8; // "00000000"
+ if( !( inFlags & kDebugFlagsNoOffset ) )
+ {
+ width += 1; // "+"
+ }
+ }
+ if( inFlags & kDebugFlags32BitOffset )
+ {
+ width += 8; // "00000000"
+ }
+ else if( !( inFlags & kDebugFlagsNoOffset ) )
+ {
+ width += 4; // "0000"
+ }
+
+ if( outBuffer )
+ {
+ dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s",
+ width, "",
+ ( width > 0 ) ? ": " : "",
+ width, (int) inLabelSize, inLabel,
+ newline );
+ }
+ else
+ {
+ dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s",
+ width, "",
+ ( width > 0 ) ? ": " : "",
+ width, (int) inLabelSize, inLabel,
+ newline );
+ }
+ }
+ break;
+ }
+
+ // Build the prefix string. It will be in one of the following formats:
+ //
+ // 1) "00000000+0000[0000]" (address and offset)
+ // 2) "00000000" (address only)
+ // 3) "0000[0000]" (offset only)
+ // 4) "" (no address or offset)
+ //
+ // Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate.
+
+ s = prefixString;
+ if( !( inFlags & kDebugFlagsNoAddress ) )
+ {
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 8 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 4 ) & 0xF ];
+ *s++ = kHexChars[ ( (uintptr_t) src ) & 0xF ];
+
+ if( !( inFlags & kDebugFlagsNoOffset ) )
+ {
+ *s++ = '+';
+ }
+ }
+ if( !( inFlags & kDebugFlagsNoOffset ) )
+ {
+ if( inFlags & kDebugFlags32BitOffset )
+ {
+ *s++ = kHexChars[ ( offset >> 28 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 24 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 20 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 16 ) & 0xF ];
+ }
+ *s++ = kHexChars[ ( offset >> 12 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 8 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 4 ) & 0xF ];
+ *s++ = kHexChars[ offset & 0xF ];
+ }
+ if( s != prefixString )
+ {
+ *s++ = ':';
+ *s++ = ' ';
+ }
+ check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) );
+ *s = '\0';
+
+ // Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read.
+ // Optionally pads the hex string with space to fill the full 16 byte range (so it lines up).
+
+ s = hexString;
+ chunkSize = ( inDataSize < 16 ) ? inDataSize : 16;
+ n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16;
+ for( i = 0; i < n; ++i )
+ {
+ if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) )
+ {
+ *s++ = ' ';
+ }
+ if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) )
+ {
+ *s++ = ' ';
+ }
+ if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) )
+ {
+ *s++ = ' ';
+ }
+ if( i < chunkSize )
+ {
+ *s++ = kHexChars[ src[ i ] >> 4 ];
+ *s++ = kHexChars[ src[ i ] & 0xF ];
+ }
+ else
+ {
+ *s++ = ' ';
+ *s++ = ' ';
+ }
+ }
+ check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) );
+ *s = '\0';
+
+ // Build a string with the ASCII version of the data (replaces non-printable characters with '^').
+ // Optionally pads the string with '`' to fill the full 16 byte range (so it lines up).
+
+ s = asciiString;
+ if( !( inFlags & kDebugFlagsNoASCII ) )
+ {
+ *s++ = ' ';
+ *s++ = '|';
+ for( i = 0; i < n; ++i )
+ {
+ if( i < chunkSize )
+ {
+ c = src[ i ];
+ if( !DebugIsPrint( c ) )
+ {
+ c = '^';
+ }
+ }
+ else
+ {
+ c = '`';
+ }
+ *s++ = (char) c;
+ }
+ *s++ = '|';
+ check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) );
+ }
+ *s = '\0';
+
+ // Build a string indicating how bytes are in the hex dump. Only printed on the first line.
+
+ s = byteCountString;
+ if( !( inFlags & kDebugFlagsNoByteCount ) )
+ {
+ if( src == start )
+ {
+ s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize );
+ }
+ }
+ check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) );
+ *s = '\0';
+
+ // Build the entire line from all the pieces we've previously built.
+
+ if( outBuffer )
+ {
+ if( src == start )
+ {
+ dst += DebugSNPrintF( dst, (size_t)( end - dst ),
+ "%*s" // Indention
+ "%s" // Separator (only if needed)
+ "%s" // Prefix
+ "%-*.*s" // Label
+ "%s" // Separator
+ "%s" // Hex
+ "%s" // ASCII
+ "%s" // Byte Count
+ "%s", // Newline
+ inIndent, "",
+ ( src != start ) ? separator : "",
+ prefixString,
+ width, (int) inLabelSize, inLabel ? inLabel : "",
+ ( width > 0 ) ? " " : "",
+ hexString,
+ asciiString,
+ byteCountString,
+ newline );
+ }
+ else
+ {
+ dst += DebugSNPrintF( dst, (size_t)( end - dst ),
+ "%*s" // Indention
+ "%s" // Separator (only if needed)
+ "%s" // Prefix
+ "%*s" // Label Spacing
+ "%s" // Separator
+ "%s" // Hex
+ "%s" // ASCII
+ "%s" // Byte Count
+ "%s", // Newline
+ inIndent, "",
+ ( src != start ) ? separator : "",
+ prefixString,
+ width, "",
+ ( width > 0 ) ? " " : "",
+ hexString,
+ asciiString,
+ byteCountString,
+ newline );
+ }
+ }
+ else
+ {
+ if( src == start )
+ {
+ dst += DebugPrintF( inLevel,
+ "%*s" // Indention
+ "%s" // Separator (only if needed)
+ "%s" // Prefix
+ "%-*.*s" // Label
+ "%s" // Separator
+ "%s" // Hex
+ "%s" // ASCII
+ "%s" // Byte Count
+ "%s", // Newline
+ inIndent, "",
+ ( src != start ) ? separator : "",
+ prefixString,
+ width, (int) inLabelSize, inLabel,
+ ( width > 0 ) ? " " : "",
+ hexString,
+ asciiString,
+ byteCountString,
+ newline );
+ }
+ else
+ {
+ dst += DebugPrintF( inLevel,
+ "%*s" // Indention
+ "%s" // Separator (only if needed)
+ "%s" // Prefix
+ "%*s" // Label Spacing
+ "%s" // Separator
+ "%s" // Hex
+ "%s" // ASCII
+ "%s" // Byte Count
+ "%s", // Newline
+ inIndent, "",
+ ( src != start ) ? separator : "",
+ prefixString,
+ width, "",
+ ( width > 0 ) ? " " : "",
+ hexString,
+ asciiString,
+ byteCountString,
+ newline );
+ }
+ }
+
+ // Move to the next chunk. Exit if there is no more data.
+
+ offset += (int) chunkSize;
+ src += chunkSize;
+ inDataSize -= chunkSize;
+ if( inDataSize == 0 )
+ {
+ break;
+ }
+ }
+
+ // Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative.
+
+ return( (size_t)( dst - outBuffer ) );
+}
+
+//===========================================================================================================================
+// DebugNumVersionToString
+//===========================================================================================================================
+
+static char * DebugNumVersionToString( uint32_t inVersion, char *inString )
+{
+ char * s;
+ uint8_t majorRev;
+ uint8_t minor;
+ uint8_t bugFix;
+ uint8_t stage;
+ uint8_t revision;
+
+ check( inString );
+
+ majorRev = (uint8_t)( ( inVersion >> 24 ) & 0xFF );
+ minor = (uint8_t)( ( inVersion >> 20 ) & 0x0F );
+ bugFix = (uint8_t)( ( inVersion >> 16 ) & 0x0F );
+ stage = (uint8_t)( ( inVersion >> 8 ) & 0xFF );
+ revision = (uint8_t)( inVersion & 0xFF );
+
+ // Convert the major, minor, and bugfix numbers.
+
+ s = inString;
+ s += sprintf( s, "%u", majorRev );
+ s += sprintf( s, ".%u", minor );
+ if( bugFix != 0 )
+ {
+ s += sprintf( s, ".%u", bugFix );
+ }
+
+ // Convert the version stage and non-release revision number.
+
+ switch( stage )
+ {
+ case kVersionStageDevelopment:
+ s += sprintf( s, "d%u", revision );
+ break;
+
+ case kVersionStageAlpha:
+ s += sprintf( s, "a%u", revision );
+ break;
+
+ case kVersionStageBeta:
+ s += sprintf( s, "b%u", revision );
+ break;
+
+ case kVersionStageFinal:
+
+ // A non-release revision of zero is a special case indicating the software is GM (at the golden master
+ // stage) and therefore, the non-release revision should not be added to the string.
+
+ if( revision != 0 )
+ {
+ s += sprintf( s, "f%u", revision );
+ }
+ break;
+
+ default:
+ dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage );
+ break;
+ }
+ return( inString );
+}
+
+//===========================================================================================================================
+// DebugTaskLevel
+//===========================================================================================================================
+
+DEBUG_EXPORT uint32_t DebugTaskLevel( void )
+{
+ uint32_t level;
+
+ level = 0;
+
+#if( TARGET_OS_VXWORKS )
+ if( intContext() )
+ {
+ level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
+ }
+#endif
+
+ return( level );
+}
+
+#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+// DebugWinEnableConsole
+//===========================================================================================================================
+
+#pragma warning( disable:4311 )
+
+static void DebugWinEnableConsole( void )
+{
+ static bool sConsoleEnabled = false;
+ BOOL result;
+ int fileHandle;
+ FILE * file;
+ int err;
+
+ if( sConsoleEnabled )
+ {
+ goto exit;
+ }
+
+ // Create console window.
+
+ result = AllocConsole();
+ require_quiet( result, exit );
+
+ // Redirect stdin to the console stdin.
+
+ fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT );
+
+ #if( defined( __MWERKS__ ) )
+ file = __handle_reopen( (unsigned long) fileHandle, "r", stdin );
+ require_quiet( file, exit );
+ #else
+ file = _fdopen( fileHandle, "r" );
+ require_quiet( file, exit );
+
+ *stdin = *file;
+ #endif
+
+ err = setvbuf( stdin, NULL, _IONBF, 0 );
+ require_noerr_quiet( err, exit );
+
+ // Redirect stdout to the console stdout.
+
+ fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
+
+ #if( defined( __MWERKS__ ) )
+ file = __handle_reopen( (unsigned long) fileHandle, "w", stdout );
+ require_quiet( file, exit );
+ #else
+ file = _fdopen( fileHandle, "w" );
+ require_quiet( file, exit );
+
+ *stdout = *file;
+ #endif
+
+ err = setvbuf( stdout, NULL, _IONBF, 0 );
+ require_noerr_quiet( err, exit );
+
+ // Redirect stderr to the console stdout.
+
+ fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
+
+ #if( defined( __MWERKS__ ) )
+ file = __handle_reopen( (unsigned long) fileHandle, "w", stderr );
+ require_quiet( file, exit );
+ #else
+ file = _fdopen( fileHandle, "w" );
+ require_quiet( file, exit );
+
+ *stderr = *file;
+ #endif
+
+ err = setvbuf( stderr, NULL, _IONBF, 0 );
+ require_noerr_quiet( err, exit );
+
+ sConsoleEnabled = true;
+
+exit:
+ return;
+}
+
+#pragma warning( default:4311 )
+
+#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
+
+#if( TARGET_OS_WIN32 )
+//===========================================================================================================================
+// DebugWinCharToTCharString
+//===========================================================================================================================
+
+static TCHAR *
+ DebugWinCharToTCharString(
+ const char * inCharString,
+ size_t inCharCount,
+ TCHAR * outTCharString,
+ size_t inTCharCountMax,
+ size_t * outTCharCount )
+{
+ const char * src;
+ TCHAR * dst;
+ TCHAR * end;
+
+ if( inCharCount == kSizeCString )
+ {
+ inCharCount = strlen( inCharString );
+ }
+ src = inCharString;
+ dst = outTCharString;
+ if( inTCharCountMax > 0 )
+ {
+ inTCharCountMax -= 1;
+ if( inTCharCountMax > inCharCount )
+ {
+ inTCharCountMax = inCharCount;
+ }
+
+ end = dst + inTCharCountMax;
+ while( dst < end )
+ {
+ *dst++ = (TCHAR) *src++;
+ }
+ *dst = 0;
+ }
+ if( outTCharCount )
+ {
+ *outTCharCount = (size_t)( dst - outTCharString );
+ }
+ return( outTCharString );
+}
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == Debugging ==
+#endif
+
+//===========================================================================================================================
+// DebugServicesTest
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus DebugServicesTest( void )
+{
+ OSStatus err;
+ char s[ 512 ];
+ uint8_t * p;
+ uint8_t data[] =
+ {
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66,
+ 0x77, 0x88, 0x99, 0xAA,
+ 0xBB, 0xCC, 0xDD,
+ 0xEE,
+ 0xFF,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0,
+ 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1
+ };
+
+ debug_initialize( kDebugOutputTypeMetaConsole );
+
+ // check's
+
+ check( 0 && "SHOULD SEE: check" );
+ check( 1 && "SHOULD *NOT* SEE: check (valid)" );
+ check_string( 0, "SHOULD SEE: check_string" );
+ check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" );
+ check_noerr( -123 );
+ check_noerr( 10038 );
+ check_noerr( 22 );
+ check_noerr( 0 );
+ check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" );
+ check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" );
+ check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 );
+ check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 );
+ check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 );
+ check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 );
+ check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 5, 10 );
+ check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12, 6 );
+ check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 6, 10, 10 );
+ check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 );
+ check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 );
+ check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 );
+ check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 );
+
+ // require's
+
+ require( 0 && "SHOULD SEE", require1 );
+ { err = kResponseErr; goto exit; }
+require1:
+ require( 1 && "SHOULD *NOT* SEE", require2 );
+ goto require2Good;
+require2:
+ { err = kResponseErr; goto exit; }
+require2Good:
+ require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" );
+ { err = kResponseErr; goto exit; }
+require3:
+ require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" );
+ goto require4Good;
+require4:
+ { err = kResponseErr; goto exit; }
+require4Good:
+ require_quiet( 0 && "SHOULD SEE", require5 );
+ { err = kResponseErr; goto exit; }
+require5:
+ require_quiet( 1 && "SHOULD *NOT* SEE", require6 );
+ goto require6Good;
+require6:
+ { err = kResponseErr; goto exit; }
+require6Good:
+ require_noerr( -1, require7 );
+ { err = kResponseErr; goto exit; }
+require7:
+ require_noerr( 0, require8 );
+ goto require8Good;
+require8:
+ { err = kResponseErr; goto exit; }
+require8Good:
+ require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string");
+ { err = kResponseErr; goto exit; }
+require9:
+ require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" );
+ goto require10Good;
+require10:
+ { err = kResponseErr; goto exit; }
+require10Good:
+ require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" );
+ { err = kResponseErr; goto exit; }
+require11:
+ require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" );
+ goto require12Good;
+require12:
+ { err = kResponseErr; goto exit; }
+require12Good:
+ require_noerr_quiet( -4, require13 );
+ { err = kResponseErr; goto exit; }
+require13:
+ require_noerr_quiet( 0, require14 );
+ goto require14Good;
+require14:
+ { err = kResponseErr; goto exit; }
+require14Good:
+ require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) );
+ { err = kResponseErr; goto exit; }
+require15:
+ require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) );
+ goto require16Good;
+require16:
+ { err = kResponseErr; goto exit; }
+require16Good:
+ require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) );
+ { err = kResponseErr; goto exit; }
+require17:
+ require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) );
+ goto require18Good;
+require18:
+ { err = kResponseErr; goto exit; }
+require18Good:
+ require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) );
+ { err = kResponseErr; goto exit; }
+require19:
+ require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) );
+ goto require20Good;
+require20:
+ { err = kResponseErr; goto exit; }
+require20Good:
+ require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) );
+ { err = kResponseErr; goto exit; }
+require21:
+ require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) );
+ goto require22Good;
+require22:
+ { err = kResponseErr; goto exit; }
+require22Good:
+ require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" );
+ { err = kResponseErr; goto exit; }
+require23:
+ require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" );
+ goto require24Good;
+require24:
+ { err = kResponseErr; goto exit; }
+require24Good:
+
+#if( defined( __MWERKS__ ) )
+ #if( defined( __cplusplus ) && __option( exceptions ) )
+ #define COMPILER_HAS_EXCEPTIONS 1
+ #else
+ #define COMPILER_HAS_EXCEPTIONS 0
+ #endif
+#else
+ #if( defined( __cplusplus ) )
+ #define COMPILER_HAS_EXCEPTIONS 1
+ #else
+ #define COMPILER_HAS_EXCEPTIONS 0
+ #endif
+#endif
+
+#if( COMPILER_HAS_EXCEPTIONS )
+ try
+ {
+ require_throw( 1 && "SHOULD *NOT* SEE" );
+ require_throw( 0 && "SHOULD SEE" );
+ }
+ catch( ... )
+ {
+ goto require26Good;
+ }
+ { err = kResponseErr; goto exit; }
+require26Good:
+#endif
+
+ // translate_errno
+
+ err = translate_errno( 1 != -1, -123, -567 );
+ require( ( err == 0 ) && "SHOULD *NOT* SEE", exit );
+
+ err = translate_errno( -1 != -1, -123, -567 );
+ require( ( err == -123 ) && "SHOULD *NOT* SEE", exit );
+
+ err = translate_errno( -1 != -1, 0, -567 );
+ require( ( err == -567 ) && "SHOULD *NOT* SEE", exit );
+
+ // debug_string
+
+ debug_string( "debug_string" );
+
+ // DebugSNPrintF
+
+ DebugSNPrintF( s, sizeof( s ), "%d", 1234 );
+ require_action( strcmp( s, "1234" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 );
+ require_action( strcmp( s, "2345" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" );
+ require_action( strcmp( s, "test" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" );
+ require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) );
+ require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) );
+ require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 );
+
+ #if( TYPE_LONGLONG_NATIVE )
+ DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) );
+ require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) );
+ require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) );
+ require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 );
+ #endif
+
+ DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) );
+ require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 ); // 'AbCd'
+ require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 );
+
+ #if( defined( MDNS_DEBUGMSGS ) )
+ {
+ mDNSAddr maddr;
+
+ memset( &maddr, 0, sizeof( maddr ) );
+ maddr.type = mDNSAddrType_IPv4;
+ maddr.ip.v4.b[ 0 ] = 127;
+ maddr.ip.v4.b[ 1 ] = 0;
+ maddr.ip.v4.b[ 2 ] = 0;
+ maddr.ip.v4.b[ 3 ] = 1;
+ DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
+ require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 );
+
+ memset( &maddr, 0, sizeof( maddr ) );
+ maddr.type = mDNSAddrType_IPv6;
+ maddr.ip.v6.b[ 0 ] = 0xFE;
+ maddr.ip.v6.b[ 1 ] = 0x80;
+ maddr.ip.v6.b[ 15 ] = 0x01;
+ DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
+ require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 );
+ }
+ #endif
+
+ #if( AF_INET )
+ {
+ struct sockaddr_in sa4;
+
+ memset( &sa4, 0, sizeof( sa4 ) );
+ sa4.sin_family = AF_INET;
+ p = (uint8_t *) &sa4.sin_port;
+ p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF );
+ p[ 1 ] = (uint8_t)( 80 & 0xFF );
+ p = (uint8_t *) &sa4.sin_addr.s_addr;
+ p[ 0 ] = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF );
+ p[ 1 ] = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF );
+ p[ 2 ] = (uint8_t)( ( INADDR_LOOPBACK >> 8 ) & 0xFF );
+ p[ 3 ] = (uint8_t)( INADDR_LOOPBACK & 0xFF );
+ DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 );
+ require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 );
+ }
+ #endif
+
+ #if( AF_INET6 )
+ {
+ struct sockaddr_in6 sa6;
+
+ memset( &sa6, 0, sizeof( sa6 ) );
+ sa6.sin6_family = AF_INET6;
+ p = (uint8_t *) &sa6.sin6_port;
+ p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF );
+ p[ 1 ] = (uint8_t)( 80 & 0xFF );
+ sa6.sin6_addr.s6_addr[ 0 ] = 0xFE;
+ sa6.sin6_addr.s6_addr[ 1 ] = 0x80;
+ sa6.sin6_addr.s6_addr[ 15 ] = 0x01;
+ sa6.sin6_scope_id = 2;
+ DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 );
+ require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 );
+ }
+ #endif
+
+ // Unicode
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" );
+ require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" );
+ require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" );
+ require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" );
+ require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" );
+ require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" );
+ require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" );
+ require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" );
+ require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" );
+ require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" );
+ require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" );
+ require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" );
+ require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" );
+ require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+ #if( TARGET_RT_BIG_ENDIAN )
+ DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+ #else
+ DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+ #endif
+
+ DebugSNPrintF( s, sizeof( s ), "%S",
+ "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%S",
+ "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%.*S",
+ 4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian BOM
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%.*S",
+ 4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian BOM
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+
+ #if( TARGET_RT_BIG_ENDIAN )
+ DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+ #else
+ DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+ #endif
+
+ DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+
+ // Misc
+
+ DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" );
+ require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%m", 0 );
+ require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 );
+ require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 );
+ DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+
+ DebugSNPrintF( s, sizeof( s ), "\"%H\"",
+ "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
+ "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8",
+ 32, 32 );
+ DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+
+ DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 );
+ DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+
+ // Hex Dumps
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNone, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoOffset, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoOffset, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoByteCount, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4, // 'AbCd'
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
+ kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount,
+ s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine |
+ kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator |
+ kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ // dlog's
+
+ dlog( kDebugLevelNotice, "dlog\n" );
+ dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 );
+ dlog( kDebugLevelNotice, "dlog string: \"%s\"\n", "test string" );
+ dlogmem( kDebugLevelNotice, data, sizeof( data ) );
+
+ // Done
+
+ DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" );
+ err = kNoErr;
+
+exit:
+ if( err )
+ {
+ DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" );
+ }
+ return( err );
+}
+
+#endif // DEBUG
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: DebugServices.h,v $
+Revision 1.5 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.4 2004/04/15 08:59:08 bradley
+Removed deprecated debug and log levels and replaced them with modern equivalents.
+
+Revision 1.3 2004/04/08 09:29:55 bradley
+Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
+hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
+Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
+
+Revision 1.2 2004/03/07 05:59:34 bradley
+Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
+
+Revision 1.1 2004/01/30 02:27:30 bradley
+Debugging support for various platforms.
+
+*/
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @header DebugServices
+
+ Debugging Library
+*/
+
+#ifndef __DEBUG_SERVICES__
+#define __DEBUG_SERVICES__
+
+#include <stdarg.h>
+
+#include "CommonServices.h"
+
+#if( TARGET_OS_VXWORKS )
+ #include "logLib.h"
+#endif
+
+#if 0
+#pragma mark == Settings ==
+#endif
+
+//===========================================================================================================================
+// Settings
+//===========================================================================================================================
+
+// General
+
+#if( !defined( DEBUG ) )
+ #define DEBUG 0
+#endif
+
+#if( defined( NDEBUG ) && DEBUG )
+ #error NDEBUG defined and DEBUG is also enabled...they need to be in-sync
+#endif
+
+// AssertMacros.h/Debugging.h overrides.
+
+#if( !defined( DEBUG_OVERRIDE_APPLE_MACROS ) )
+ #define DEBUG_OVERRIDE_APPLE_MACROS 1
+#endif
+
+// Routine name. Uses ISO __func__ where possible. Otherwise, uses the best thing that is available (if anything).
+
+#if( defined( __MWERKS__ ) || ( __GNUC__ > 2 ) || ( ( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 9 ) ) )
+ #define __ROUTINE__ __func__
+#elif( defined( __GNUC__ ) )
+ #define __ROUTINE__ __PRETTY_FUNCTION__
+#elif( defined( _MSC_VER ) && !defined( _WIN32_WCE ) )
+ #define __ROUTINE__ __FUNCTION__
+#else
+ #define __ROUTINE__ ""
+#endif
+
+// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing.
+
+#if( defined( __GNUC__ ) )
+ #if( ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 3) ) )
+ #define DEBUG_C99_VA_ARGS 1
+ #define DEBUG_GNU_VA_ARGS 0
+ #else
+ #define DEBUG_C99_VA_ARGS 0
+ #define DEBUG_GNU_VA_ARGS 1
+ #endif
+#elif( defined( __MWERKS__ ) )
+ #define DEBUG_C99_VA_ARGS 1
+ #define DEBUG_GNU_VA_ARGS 0
+#else
+ #define DEBUG_C99_VA_ARGS 0
+ #define DEBUG_GNU_VA_ARGS 0
+#endif
+
+#if 0
+#pragma mark == Output ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_FPRINTF_ENABLED
+
+ @abstract Enables ANSI C fprintf output.
+*/
+
+#if( !defined( DEBUG_FPRINTF_ENABLED ) )
+ #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
+ #define DEBUG_FPRINTF_ENABLED 1
+ #else
+ #define DEBUG_FPRINTF_ENABLED 0
+ #endif
+#else
+ #if( TARGET_API_MAC_OSX_KERNEL || TARGET_OS_WINDOWS_CE )
+ #error fprintf enabled, but not supported on Mac OS X kernel or Windows CE
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_MAC_OS_X_IOLOG_ENABLED
+
+ @abstract Enables IOLog (Mac OS X Kernel) output.
+*/
+
+#if( !defined( DEBUG_MAC_OS_X_IOLOG_ENABLED ) )
+ #define DEBUG_MAC_OS_X_IOLOG_ENABLED TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_KPRINTF_ENABLED
+
+ @abstract Enables kprintf (Mac OS X Kernel) output.
+*/
+
+#if( !defined( DEBUG_KPRINTF_ENABLED ) )
+ #define DEBUG_KPRINTF_ENABLED TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_IDEBUG_ENABLED
+
+ @abstract Enables iDebug (Mac OS X user and Kernel) output.
+
+ @discussion
+
+ For Mac OS X kernel development, iDebug is enabled by default because we can dynamically check for the presence
+ of iDebug via some exported IOKit symbols. Mac OS X app usage doesn't allow dynamic detection because it relies
+ on statically linking to the iDebugServices.cp file so for Mac OS X app usage, you have to manually enable iDebug.
+*/
+
+#if( !defined( DEBUG_IDEBUG_ENABLED ) )
+ #define DEBUG_IDEBUG_ENABLED TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_CORE_SERVICE_ASSERTS_ENABLED
+
+ @abstract Controls whether Core Services assert handling is enabled. Enabling requires CoreServices framework.
+*/
+
+#if( !defined( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) )
+ #if( defined( __DEBUGGING__ ) )
+ #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED 1
+ #else
+ #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED 0
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugOutputType
+
+ @abstract Type of debug output (i.e. where the output goes).
+*/
+
+typedef uint32_t DebugOutputType;
+
+#define kDebugOutputTypeNone 0x6E6F6E65U // 'none' - no params
+#define kDebugOutputTypeCustom 0x63757374U // 'cust' - 1st param = function ptr, 2nd param = context
+#define kDebugOutputTypeFPrintF 0x66707269U // 'fpri' - 1st param = DebugOutputTypeFlags [, 2nd param = filename]
+#define kDebugOutputTypeiDebug 0x69646267U // 'idbg' - no params
+#define kDebugOutputTypeKPrintF 0x6B707266U // 'kprf' - no params
+#define kDebugOutputTypeMacOSXIOLog 0x696C6F67U // 'ilog' - no params
+#define kDebugOutputTypeMacOSXLog 0x786C6F67U // 'xlog' - no params
+#define kDebugOutputTypeWindowsDebugger 0x77696E64U // 'wind' - no params
+#define kDebugOutputTypeWindowsEventLog 0x7765766CU // 'wevl' - 1st param = C-string name, 2nd param = HMODULE or NULL.
+
+// Console meta output kind - Any kind of Console output (in horizontal order of preference):
+//
+// Mac OS X = ANSI printf (viewable in Console.app)
+// Mac OS X Kernel = IOLog (/var/log/system.log) or kprintf (serial).
+// Windows = ANSI printf (Console window) or OutputDebugString (debugger).
+// Other = ANSI printf (viewer varies).
+
+#define kDebugOutputTypeMetaConsole 0x434F4E53U // 'CONS' - no params
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugOutputTypeFlags
+
+ @abstract Flags controlling how the output type is configured.
+
+ @constant kDebugOutputTypeFlagsTypeMask Bit mask for the output type (e.g. stdout, stderr, file, etc.).
+ @constant kDebugOutputTypeFlagsStdOut fprintf should go to stdout.
+ @constant kDebugOutputTypeFlagsStdErr fprintf should go to stderr.
+ @constant kDebugOutputTypeFlagsFile fprintf should go to a specific file (filename passed as va_arg).
+*/
+
+typedef unsigned int DebugOutputTypeFlags;
+
+#define kDebugOutputTypeFlagsTypeMask 0xF
+#define kDebugOutputTypeFlagsStdOut 1
+#define kDebugOutputTypeFlagsStdErr 2
+#define kDebugOutputTypeFlagsFile 10
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugOutputFunctionPtr
+
+ @abstract Function ptr for a custom callback to print debug output.
+*/
+
+typedef void ( *DebugOutputFunctionPtr )( char *inData, size_t inSize, void *inContext );
+
+//===========================================================================================================================
+// Constants
+//===========================================================================================================================
+
+#if 0
+#pragma mark == Flags ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugFlags
+
+ @abstract Flags controlling how output is printed.
+*/
+
+typedef uint32_t DebugFlags;
+
+#define kDebugFlagsNone 0
+#define kDebugFlagsNoAddress ( 1 << 0 )
+#define kDebugFlagsNoOffset ( 1 << 1 )
+#define kDebugFlags32BitOffset ( 1 << 2 )
+#define kDebugFlagsNoASCII ( 1 << 3 )
+#define kDebugFlagsNoNewLine ( 1 << 4 )
+#define kDebugFlags8BitSeparator ( 1 << 5 )
+#define kDebugFlags16BitSeparator ( 1 << 6 )
+#define kDebugFlagsNo32BitSeparator ( 1 << 7 )
+#define kDebugFlagsNo16ByteHexPad ( 1 << 8 )
+#define kDebugFlagsNoByteCount ( 1 << 9 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @enum DebugTaskLevelFlags
+
+ @abstract Flags indicating the task level.
+*/
+
+enum
+{
+ kDebugInterruptLevelShift = 0,
+ kDebugInterruptLevelMask = 0x00000007,
+ kDebugInVBLTaskMask = 0x00000010,
+ kDebugInDeferredTaskMask = 0x00000020,
+ kDebugInSecondaryInterruptHandlerMask = 0x00000040,
+ kDebugPageFaultFatalMask = 0x00000100, // There should be a "kPageFaultFatalMask" in Debugging.h.
+ kDebugMPTaskLevelMask = 0x00000200, // There should be a "kMPTaskLevelMask" in Debugging.h.
+ kDebugInterruptDepthShift = 16,
+ kDebugInterruptDepthMask = 0x00FF0000
+};
+
+#define DebugExtractTaskLevelInterruptLevel( LEVEL ) \
+ ( ( ( LEVEL ) & kDebugInterruptLevelMask ) >> kDebugInterruptLevelShift )
+
+#define DebugExtractTaskLevelInterruptDepth( LEVEL ) \
+ ( ( ( LEVEL ) & kDebugInterruptDepthMask ) >> kDebugInterruptDepthShift )
+
+#if 0
+#pragma mark == Levels ==
+#endif
+
+//===========================================================================================================================
+// Constants & Types - Levels
+//===========================================================================================================================
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugLevel
+
+ @abstract Level used to control debug logging.
+*/
+
+typedef int32_t DebugLevel;
+
+// Levels
+
+#define kDebugLevelMask 0x0000FFFF
+#define kDebugLevelChatty 100
+#define kDebugLevelVerbose 500
+#define kDebugLevelTrace 800
+#define kDebugLevelInfo 1000
+#define kDebugLevelNotice 3000
+#define kDebugLevelWarning 5000
+#define kDebugLevelAssert 6000
+#define kDebugLevelRequire 7000
+#define kDebugLevelError 8000
+#define kDebugLevelCritical 9000
+#define kDebugLevelAlert 10000
+#define kDebugLevelEmergency 11000
+#define kDebugLevelTragic 12000
+#define kDebugLevelMax 0x0000FFFF
+
+// Level Flags
+
+#define kDebugLevelFlagMask 0xFFFF0000
+#define kDebugLevelFlagStackTrace 0x00010000
+#define kDebugLevelFlagDebugBreak 0x00020000
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef LogLevel
+
+ @abstract Level used to control which events are logged.
+*/
+
+typedef int32_t LogLevel;
+
+#define kLogLevelUninitialized -1L
+#define kLogLevelAll 0L
+#define kLogLevelChatty 100L
+#define kLogLevelVerbose 500L
+#define kLogLevelTrace 800L
+#define kLogLevelInfo 1000L
+#define kLogLevelNotice 3000L
+#define kLogLevelWarning 4000L
+#define kLogLevelAssert 6000L
+#define kLogLevelRequire 7000L
+#define kLogLevelError 8000L
+#define kLogLevelCritical 9000L
+#define kLogLevelAlert 10000L
+#define kLogLevelEmergency 11000L
+#define kLogLevelTragic 12000L
+#define kLogLevelOff 0x0000FFFEL
+
+#if 0
+#pragma mark == Properties ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugPropertyTag
+
+ @abstract Tag for properties.
+*/
+
+typedef uint32_t DebugPropertyTag;
+
+#define kDebugPropertyTagPrintLevelMin 0x6D696E70U // 'minp' Get: 1st param = DebugLevel *
+ // Set: 1st param = DebugLevel
+
+#define kDebugPropertyTagPrintLevel kDebugPropertyTagPrintLevelMin
+
+#define kDebugPropertyTagPrintLevelMax 0x706D786CU // 'maxp' Get: 1st param = DebugLevel *
+ // Set: 1st param = DebugLevel
+
+#define kDebugPropertyTagBreakLevel 0x62726B6CU // 'brkl' Get: 1st param = DebugLevel *
+ // Set: 1st param = DebugLevel
+#if 0
+#pragma mark == General macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_UNUSED
+
+ @abstract Macro to mark a paramter as unused to avoid unused parameter warnings.
+
+ @discussion
+
+ There is no universally supported pragma/attribute for indicating a variable is unused. DEBUG_UNUSED lets us
+ indicate a variable is unused in a manner that is supported by most compilers.
+*/
+
+#define DEBUG_UNUSED( X ) (void)( X )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_USE_ONLY
+
+ @abstract Macro to mark a variable as used only when debugging is enabled.
+
+ @discussion
+
+ Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables generate
+ compiler warnings about unused variables. To eliminate these warnings, use these macros to indicate variables that
+ are only used for debugging.
+*/
+
+#if( DEBUG )
+ #define DEBUG_USE_ONLY( X )
+#else
+ #define DEBUG_USE_ONLY( X ) (void)( X )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_LOCAL
+
+ @abstract Macros to make variables and functions static when debugging is off, but extern when debugging is on.
+
+ @discussion
+
+ Rather than using "static" directly, using this macros allows you to access these variables external while
+ debugging without being penalized for production builds.
+*/
+
+#if( DEBUG )
+ #define DEBUG_LOCAL
+#else
+ #define DEBUG_LOCAL static
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_STATIC
+
+ @abstract Macros to make variables and functions static when debugging is off, but extern when debugging is on.
+
+ @discussion
+
+ Rather than using "static" directly, using this macros allows you to access these variables external while
+ debugging without being penalized for production builds.
+*/
+
+#if( DEBUG )
+ #define DEBUG_STATIC
+#else
+ #define DEBUG_STATIC static
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_EXPORT
+
+ @abstract Macros to export variables.
+
+ @discussion
+
+ "__private_extern__" is a hack for IOKit to allow symbols to be exported from compilation units, but
+ // not exported outside a driver (IOKit uses a lame global namespace for symbols). This still does not
+ // solve the problem of multiple drivers in the same dependency chain since they share symbols.
+*/
+
+#if( TARGET_API_MAC_OSX_KERNEL )
+ #define DEBUG_EXPORT __private_extern__
+#else
+ #define DEBUG_EXPORT extern
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined debug_add
+
+ @abstract Macro to add (or subtract if negative) a value when debugging is on. Does nothing if debugging is off.
+*/
+
+#if( DEBUG )
+ #define debug_add( A, B ) ( A ) += ( B )
+#else
+ #define debug_add( A, B )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined debug_perform
+
+ @abstract Macro to perform something in debug-only builds.
+*/
+
+#if( DEBUG )
+ #define debug_perform( X ) do { X; } while( 0 )
+#else
+ #define debug_perform( X )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function translate_errno
+
+ @abstract Returns 0 if the test success. If the test fails, returns errno if non-zero and othewise the alternate error.
+*/
+
+#define translate_errno( TEST, ERRNO, ALTERNATE_ERROR ) ( ( TEST ) ? 0 : ( ERRNO ) ? ( ERRNO ) : ( ALTERNATE_ERROR ) )
+
+#if 0
+#pragma mark == Compile Time macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_compile_time
+
+ @abstract Performs a compile-time check of something such as the size of an int.
+
+ @discussion
+
+ This declares an array with a size that is determined by a compile-time expression. If the expression evaluates
+ to 0, the array has a size of -1, which is illegal and generates a compile-time error.
+
+ For example:
+
+ check_compile_time( sizeof( int ) == 4 );
+
+ Note: This only works with compile-time expressions.
+ Note: This only works in places where extern declarations are allowed (e.g. global scope).
+
+ References:
+
+ <http://www.jaggersoft.com/pubs/CVu11_3.html>
+ <http://www.jaggersoft.com/pubs/CVu11_5.html>
+
+ Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not
+ work with GCC due to GCC allow a zero-length array. Using a -1 condition turned out to be more portable.
+*/
+
+#define check_compile_time( X ) extern int debug_compile_time_name[ ( X ) ? 1 : -1 ]
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_compile_time_code
+
+ @abstract Perform a compile-time check, suitable for placement in code, of something such as the size of an int.
+
+ @discussion
+
+ This creates a switch statement with an existing case for 0 and an additional case using the result of a
+ compile-time expression. A switch statement cannot have two case labels with the same constant so if the
+ compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time
+ expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error.
+
+ For example:
+
+ check_compile_time_code( sizeof( int ) == 4 );
+
+ Note: This only works with compile-time expressions.
+ Note: This does not work in a global scope so it must be inside a function.
+
+ References:
+
+ <http://www.jaggersoft.com/pubs/CVu11_3.html>
+ <http://www.jaggersoft.com/pubs/CVu11_5.html>
+*/
+
+#define check_compile_time_code( X ) switch( 0 ) { case 0: case X:; }
+
+#if 0
+#pragma mark == check macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check
+
+ @abstract Check that an expression is true (non-zero).
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method.
+
+ Code inside check() statements is not compiled into production builds.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef check
+#endif
+#if( !defined( check ) )
+ #if( DEBUG )
+ #define check( X ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ } while( 0 )
+ #else
+ #define check( X )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_string
+
+ @abstract Check that an expression is true (non-zero) with an explanation.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) and a custom explanation string using the default debugging output method.
+
+ Code inside check_string() statements is not compiled into production builds.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef check_string
+#endif
+#if( !defined( check_string ) )
+ #if( DEBUG )
+ #define check_string( X, STR ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define check_string( X, STR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_noerr
+
+ @abstract Check that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method.
+
+ Code inside check_noerr() statements is not compiled into production builds.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef check_noerr
+#endif
+#if( !defined( check_noerr ) )
+ #if( DEBUG )
+ #define check_noerr( ERR ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define check_noerr( ERR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_noerr_string
+
+ @abstract Check that an error code is noErr (0) with an explanation.
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) and a custom explanation string using the default debugging output method.
+
+ Code inside check_noerr_string() statements is not compiled into production builds.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef check_noerr_string
+#endif
+#if( !defined( check_noerr_string ) )
+ #if( DEBUG )
+ #define check_noerr_string( ERR, STR ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define check_noerr_string( ERR, STR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_translated_errno
+
+ @abstract Check a condition and prints errno (if non-zero) to the log.
+
+ @discussion
+
+ Code inside check_translated_errno() statements is not compiled into production builds.
+*/
+
+#if( !defined( check_translated_errno ) )
+ #if( DEBUG )
+ #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) \
+ do \
+ { \
+ if( !( TEST ) ) \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERRNO ); \
+ localErr = ( localErr != 0 ) ? localErr : (int_least32_t)( ALTERNATE_ERROR ); \
+ debug_print_assert( localErr, #TEST, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_ptr_overlap
+
+ @abstract Checks that two ptrs do not overlap.
+*/
+
+#define check_ptr_overlap( P1, P1_SIZE, P2, P2_SIZE ) \
+ do \
+ { \
+ check( !( ( (uintptr_t)( P1 ) >= (uintptr_t)( P2 ) ) && \
+ ( (uintptr_t)( P1 ) < ( ( (uintptr_t)( P2 ) ) + ( P2_SIZE ) ) ) ) ); \
+ check( !( ( (uintptr_t)( P2 ) >= (uintptr_t)( P1 ) ) && \
+ ( (uintptr_t)( P2 ) < ( ( (uintptr_t)( P1 ) ) + ( P1_SIZE ) ) ) ) ); \
+ \
+ } while( 0 )
+
+#if 0
+#pragma mark == require macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require
+
+ @abstract Requires that an expression evaluate to true.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require
+#endif
+#if( !defined( require ) )
+ #define require( X, LABEL ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_string
+
+ @abstract Requires that an expression evaluate to true with an explanation.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_string
+#endif
+#if( !defined( require_string ) )
+ #define require_string( X, LABEL, STR ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_quiet
+
+ @abstract Requires that an expression evaluate to true.
+
+ @discussion
+
+ If expression evalulates to false, this jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_quiet
+#endif
+#if( !defined( require_quiet ) )
+ #define require_quiet( X, LABEL ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr
+
+ @abstract Require that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr
+#endif
+#if( !defined( require_noerr ) )
+ #define require_noerr( ERR, LABEL ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_string
+
+ @abstract Require that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.), and a custom explanation string using the default debugging output method using the
+ default debugging output method then jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_string
+#endif
+#if( !defined( require_noerr_string ) )
+ #define require_noerr_string( ERR, LABEL, STR ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_action_string
+
+ @abstract Require that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.), and a custom explanation string using the default debugging output method using the
+ default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_action_string
+#endif
+#if( !defined( require_noerr_action_string ) )
+ #define require_noerr_action_string( ERR, LABEL, ACTION, STR ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_quiet
+
+ @abstract Require that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_quiet
+#endif
+#if( !defined( require_noerr_quiet ) )
+ #define require_noerr_quiet( ERR, LABEL ) \
+ do \
+ { \
+ if( ( ERR ) != 0 ) \
+ { \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_action
+
+ @abstract Require that an error code is noErr (0) with an action to execute otherwise.
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_action
+#endif
+#if( !defined( require_noerr_action ) )
+ #define require_noerr_action( ERR, LABEL, ACTION ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_action_quiet
+
+ @abstract Require that an error code is noErr (0) with an action to execute otherwise.
+
+ @discussion
+
+ If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_action_quiet
+#endif
+#if( !defined( require_noerr_action_quiet ) )
+ #define require_noerr_action_quiet( ERR, LABEL, ACTION ) \
+ do \
+ { \
+ if( ( ERR ) != 0 ) \
+ { \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_action
+
+ @abstract Requires that an expression evaluate to true with an action to execute otherwise.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method then executes an action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_action
+#endif
+#if( !defined( require_action ) )
+ #define require_action( X, LABEL, ACTION ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_action_quiet
+
+ @abstract Requires that an expression evaluate to true with an action to execute otherwise.
+
+ @discussion
+
+ If expression evalulates to false, this executes an action and jumps to a label. No debugging information is printed.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_action_quiet
+#endif
+#if( !defined( require_action_quiet ) )
+ #define require_action_quiet( X, LABEL, ACTION ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_action_string
+
+ @abstract Requires that an expression evaluate to true with an explanation and action to execute otherwise.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) and a custom explanation string using the default debugging output method then executes an
+ action and jumps to a label.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_action_string
+#endif
+#if( !defined( require_action_string ) )
+ #define require_action_string( X, LABEL, ACTION, STR ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_throw
+
+ @abstract Requires that an expression evaluates to true or an exception is thrown.
+
+ @discussion
+
+ If the expression evaluates to false, this prints debugging information (actual expression string, file,
+ line number, function name, etc.) using the default debugging output method then throws an exception.
+*/
+
+#if( defined( __cplusplus ) )
+ #define require_throw( X ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ throw kUnknownErr; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+#if 0
+#pragma mark == Design-By-Contract macros ==
+#endif
+
+//===========================================================================================================================
+// Design-By-Contract macros
+//===========================================================================================================================
+
+#define ensure( X ) check( X )
+#define ensure_string( X, STR ) check_string( X, STR )
+#define ensure_noerr( ERR ) check_noerr( ERR )
+#define ensure_noerr_string( ERR, STR ) check_noerr_string( ERR, STR )
+#define ensure_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
+
+// Note: Design-By-Contract "require" macros are already defined elsewhere.
+
+#if 0
+#pragma mark == Expect macros ==
+#endif
+
+//===========================================================================================================================
+// Expect macros
+//===========================================================================================================================
+
+// Expect macros allow code to include runtime checking of things that should not happen in shipping code (e.g. internal
+// programmer errors, such as a NULL parameter where it is not allowed). Once the code has been verified to work correctly
+// without asserting, the DEBUG_EXPECT_VERIFIED conditional can be set to eliminate the error checking entirely. It can
+// also be useful to measure the cost of error checking code by profiling with it enable and with it disabled.
+
+#if( DEBUG_EXPECT_VERIFIED )
+ #define require_expect
+ #define require_string_expect
+ #define require_quiet_expect
+ #define require_noerr_expect
+ #define require_noerr_string_expect
+ #define require_noerr_action_string_expect
+ #define require_noerr_quiet_expect
+ #define require_noerr_action_expect
+ #define require_noerr_action_quiet_expect
+ #define require_action_expect
+ #define require_action_quiet_expect
+ #define require_action_string_expect
+#else
+ #define require_expect require
+ #define require_string_expect require_string
+ #define require_quiet_expect require_quiet
+ #define require_noerr_expect require_noerr
+ #define require_noerr_string_expect require_noerr_string
+ #define require_noerr_action_string_expect require_noerr_action_string
+ #define require_noerr_quiet_expect require_noerr_quiet
+ #define require_noerr_action_expect require_noerr_action
+ #define require_noerr_action_quiet_expect require_noerr_action_quiet
+ #define require_action_expect require_action
+ #define require_action_quiet_expect require_action_quiet
+ #define require_action_string_expect require_action_string
+#endif
+
+#if 0
+#pragma mark == Output macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined debug_string
+
+ @abstract Prints a debugging C string.
+*/
+
+#if( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef debug_string
+#endif
+#if( !defined( debug_string ) )
+ #if( DEBUG )
+ #define debug_string( STR ) \
+ do \
+ { \
+ debug_print_assert( 0, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ \
+ } while( 0 )
+ #else
+ #define debug_string( STR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined debug_print_assert
+
+ @abstract Prints an assertion.
+*/
+
+#if( DEBUG )
+ #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION ) \
+ DebugPrintAssert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
+#else
+ #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined dlog
+
+ @abstract Prints a debug-only message.
+*/
+
+#if( DEBUG )
+ #if( DEBUG_C99_VA_ARGS )
+ #define dlog( ... ) DebugPrintF( __VA_ARGS__ )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define dlog( ARGS... ) DebugPrintF( ## ARGS )
+ #else
+ #define dlog DebugPrintF
+ #endif
+#else
+ #if( DEBUG_C99_VA_ARGS )
+ #define dlog( ... )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define dlog( ARGS... )
+ #else
+ #define dlog while( 0 )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined dlogv
+
+ @abstract Prints a debug-only message.
+*/
+
+#if( DEBUG )
+ #define dlogv( LEVEL, FORMAT, LIST ) DebugPrintFVAList( ( LEVEL ), ( FORMAT ), ( LIST ) )
+#else
+ #define dlogv( LEVEL, FORMAT, LIST )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined dlogmem
+
+ @abstract Prints a debug-only dump of memory.
+*/
+
+#if( DEBUG )
+ #define dlogmem( LEVEL, PTR, SIZE ) \
+ DebugHexDump( ( LEVEL ), 0, NULL, 0, 0, NULL, 0, ( PTR ), ( PTR ), ( SIZE ), kDebugFlagsNone, NULL, 0 )
+#else
+ #define dlogmem( LEVEL, PTR, SIZE )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DebugNSLog
+
+ @abstract Debug-only macro for the Cocoa NSLog function.
+*/
+
+#if( DEBUG )
+ #if( DEBUG_C99_VA_ARGS )
+ #define DebugNSLog( ... ) NSLog( __VA_ARGS__ )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define DebugNSLog( ARGS... ) NSLog( ## ARGS )
+ #else
+ #define DebugNSLog NSLog
+ #endif
+#else
+ #if( DEBUG_C99_VA_ARGS )
+ #define DebugNSLog( ... )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define DebugNSLog( ARGS... )
+ #else
+ #define DebugNSLog while( 0 )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DebugLogMsg
+
+ @abstract Debug-only macro for the VxWorks logMsg function.
+*/
+
+#if( TARGET_OS_VXWORKS )
+ #if( DEBUG )
+ #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 ) \
+ do \
+ { \
+ if( ( inLevel >= gDebugPrintLevelMin ) || ( inLevel <= gDebugPrintLevelMax ) ) \
+ { \
+ logMsg( ( FORMAT ), ( P1 ), ( P2 ), ( P3 ), ( P4 ), ( P5 ), ( P6 ) ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )
+ #endif
+#else
+ #define DebugLogMsg dlog
+#endif
+
+#if 0
+#pragma mark == Routines - General ==
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugInitialize
+
+ @abstract Initializes the debugging library for a specific kind of output.
+
+ @param inType
+ @param varArg Variable number parameters, controlled by the "inType" parameter.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... );
+#endif
+
+#if( DEBUG )
+ #if( DEBUG_C99_VA_ARGS )
+ #define debug_initialize( ... ) DebugInitialize( __VA_ARGS__ )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define debug_initialize( ARGS... ) DebugInitialize( ## ARGS )
+ #else
+ #define debug_initialize DebugInitialize
+ #endif
+#else
+ #if( DEBUG_C99_VA_ARGS )
+ #define debug_initialize( ... )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define debug_initialize( ARGS... )
+ #else
+ #define debug_initialize while( 0 )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugFinalize
+
+ @abstract Releases any resources used by the debugging library
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT void DebugFinalize( void );
+#endif
+
+#if( DEBUG )
+ #define debug_terminate() DebugFinalize()
+#else
+ #define debug_terminate()
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugGetProperty
+
+ @abstract Gets the specified property from the debugging library.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... );
+#endif
+
+#if( DEBUG )
+ #if( DEBUG_C99_VA_ARGS )
+ #define debug_get_property( ... ) DebugGetProperty( __VA_ARGS__ )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define debug_get_property( ARGS... ) DebugGetProperty( ## ARGS )
+ #else
+ #define debug_get_property DebugGetProperty
+ #endif
+#else
+ #if( DEBUG_C99_VA_ARGS )
+ #define debug_get_property( ... )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define debug_get_property( ARGS... )
+ #else
+ #define debug_get_property while( 0 )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugSetProperty
+
+ @abstract Sets the specified property from the debugging library.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... );
+#endif
+
+#if( DEBUG )
+ #if( DEBUG_C99_VA_ARGS )
+ #define debug_set_property( ... ) DebugSetProperty( __VA_ARGS__ )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define debug_set_property( ARGS... ) DebugSetProperty( ## ARGS )
+ #else
+ #define debug_set_property DebugSetProperty
+ #endif
+#else
+ #if( DEBUG_C99_VA_ARGS )
+ #define debug_set_property( ... )
+ #elif( DEBUG_GNU_VA_ARGS )
+ #define debug_set_property( ARGS... )
+ #else
+ #define debug_set_property while( 0 )
+ #endif
+#endif
+
+#if 0
+#pragma mark == Routines - Debugging Output ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugPrintF
+
+ @abstract Prints a debug message with printf-style formatting.
+
+ @param inLevel Error that generated this assert or noErr.
+
+ @param inFormatString
+ C string containing assertion text.
+
+ @param VAR_ARG
+ Variable number of arguments depending on the format string.
+
+ @result Number of bytes printed or -1 on error.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugPrintFVAList
+
+ @abstract va_list version of DebugPrintF. See DebugPrintF for more info.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugPrintAssert
+
+ @abstract Prints a message describing the reason the (e.g. an assert failed), an optional error message,
+ an optional source filename, an optional source line number.
+
+ @param inErrorCode Error that generated this assert or noErr.
+ @param inAssertString C string containing assertion text.
+ @param inMessage C string containing a message about the assert.
+ @param inFileName C string containing path of file where the error occurred.
+ @param inLineNumber Line number in source file where the error occurred.
+ @param inFunction C string containing name of function where assert occurred.
+
+ @discussion
+
+ Example output:
+
+ [ASSERT] assert: "dataPtr != NULL" allocate memory for object failed
+ [ASSERT] where: "MyFile.c", line 123, ("MyFunction")
+
+ OR
+
+ [ASSERT] error: -6728 (kNoMemoryErr)
+ [ASSERT] where: "MyFile.c", line 123, ("MyFunction")
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT void
+ DebugPrintAssert(
+ int_least32_t inErrorCode,
+ const char * inAssertString,
+ const char * inMessage,
+ const char * inFilename,
+ int_least32_t inLineNumber,
+ const char * inFunction );
+#endif
+
+#if 0
+#pragma mark == Routines - Utilities ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugSNPrintF
+
+ @abstract Debugging versions of standard C snprintf with extra features.
+
+ @param sbuffer Buffer to receive result. Null terminated unless the buffer size is 0.
+ @param buflen Size of the buffer including space for the null terminator.
+ @param fmt printf-style format string.
+ @param VAR_ARG Variable number of arguments depending on the format string.
+
+ @result Number of characters written (minus the null terminator).
+
+ @discussion
+
+ Extra features over the standard C snprintf:
+ <pre>
+ 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
+ %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
+ %a - Network Address: %.4a=IPv4, %.6a=Ethernet, %.8a Fibre Channel, %.16a=IPv6. Arg=ptr to network address.
+ %#a - IPv4 or IPv6 mDNSAddr. Arg=ptr to mDNSAddr.
+ %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
+ %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
+ %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
+ %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+ %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+ %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code arg=the same as %d, %x, etc.
+ %#s - Pascal-style length-prefixed string. Arg=ptr to string.
+ %##s - DNS label-sequence name. Arg=ptr to name.
+ %S - UTF-16 string, 0x0000 terminated. Host order if no BOM. Precision is UTF-16 count. Precision includes BOM.
+ %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
+ %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
+ %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
+ </pre>
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...);
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugSNPrintFVAList
+
+ @abstract va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg);
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugGetErrorString
+
+ @abstract Gets an error string from an error code.
+
+ @param inStatus Error code to get the string for.
+ @param inBuffer Optional buffer to copy the string to for non-static strings. May be null.
+ @param inBufferSize Size of optional buffer. May be 0.
+
+ @result C string containing error string for the error code. Guaranteed to be a valid, static string. If a
+ buffer is supplied, the return value will always be a pointer to the supplied buffer, which will
+ contain the best available description of the error code. If a buffer is not supplied, the return
+ value will be the best available description of the error code that can be represented as a static
+ string. This allows code that cannot use a temporary buffer to hold the result to still get a useful
+ error string in most cases, but also allows code that can use a temporary buffer to get the best
+ available description.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugHexDump
+
+ @abstract Hex dumps data to a string or to the output device.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT size_t
+ DebugHexDump(
+ DebugLevel inLevel,
+ int inIndent,
+ const char * inLabel,
+ size_t inLabelSize,
+ int inLabelMinWidth,
+ const char * inType,
+ size_t inTypeSize,
+ const void * inDataStart,
+ const void * inData,
+ size_t inDataSize,
+ DebugFlags inFlags,
+ char * outBuffer,
+ size_t inBufferSize );
+#endif
+
+#if( DEBUG )
+ #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE ) \
+ DebugHexDump( ( LEVEL ), (INDENT), ( LABEL ), ( LABEL_SIZE ), ( LABEL_MIN_SIZE ), ( TYPE ), ( TYPE_SIZE ), \
+ ( DATA_START ), ( DATA ), ( DATA_SIZE ), ( FLAGS ), ( BUFFER ), ( BUFFER_SIZE ) )
+#else
+ #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugTaskLevel
+
+ @abstract Returns the current task level.
+
+ @result Current task level
+
+ @discussion
+
+ Bit masks to isolate portions of the result (note that some masks may also need bit shifts to right justify):
+ <pre>
+ kDebugInterruptLevelMask - Indicates the current interrupt level (> 0 means interrupt time).
+ kDebugInVBLTaskMask - Indicates if a VBL task is currently being executed.
+ kDebugInDeferredTaskMask - Indicates if a Deferred Task is currently being executed.
+ kDebugInSecondaryInterruptHandlerMask - Indicates if a Secondary Interrupt Handler is currently being executed.
+ kDebugPageFaultFatalMask - Indicates if it is unsafe to cause a page fault (worse than interrupt time).
+ kDebugMPTaskLevelMask - Indicates if being called from an MP task.
+ kDebugInterruptDepthMask - 0 means task level, 1 means in interrupt, > 1 means in nested interrupt.
+ </pre>
+
+ Helpers:
+ <pre>
+ DebugExtractTaskLevelInterruptDepth() - Macro to extract interrupt depth from task level value.
+ </pre>
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT uint32_t DebugTaskLevel( void );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugServicesTest
+
+ @abstract Unit test.
+*/
+
+#if( DEBUG )
+ DEBUG_EXPORT OSStatus DebugServicesTest( void );
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // __DEBUG_SERVICES__
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
File: GenLinkedList.c
Change History (most recent first):
$Log: GenLinkedList.c,v $
+Revision 1.4 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2004/04/22 21:14:42 cheshire
Fix comment spelling mistake
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
File: GenLinkedList.c
Change History (most recent first):
$Log: GenLinkedList.h,v $
+Revision 1.3 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/02/05 07:41:08 cheshire
Add Log header
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: BaseListener.java,v $
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/04/30 21:48:27 rpantos
Change line endings for CVS.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: BrowseListener.java,v $
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/04/30 21:48:27 rpantos
Change line endings for CVS.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSRecord.java,v $
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/12/11 03:00:59 rpantos
<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSSD.java,v $
+Revision 1.15 2007/03/13 00:28:03 vazquez
+<rdar://problem/4625928> Java: Rename exported symbols in libjdns_sd.jnilib
+
+Revision 1.14 2007/03/13 00:10:14 vazquez
+<rdar://problem/4455206> Java: 64 bit JNI patch
+
+Revision 1.13 2007/02/24 23:08:02 mkrochma
+<rdar://problem/5001673> Typo in Bonjour Java API document
+
+Revision 1.12 2007/02/09 00:33:02 cheshire
+Add missing error codes to kMessages array
+
+Revision 1.11 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.10 2006/06/20 23:05:55 rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
Revision 1.9 2005/10/26 01:52:24 cheshire
<rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
This file declares and implements DNSSD, the central Java factory class
for doing DNS Service Discovery. It includes the mostly-abstract public
interface, as well as the Apple* implementation subclasses.
-
- To do:
- - implement network interface mappings
- - RegisterRecord
*/
DNSSD provides access to DNS Service Discovery features of ZeroConf networking.<P>
It is a factory class that is used to invoke registration and discovery-related
- operations. Most operations are non-blocking; clients are called back through an interface
+ operations. Most operations are non-blocking; clients are called back through an interface
with the result of an operation. Callbacks are made from a separate worker thread.<P>
- For example, in this program<P>
+ For example, in this program<P>
<PRE><CODE>
class MyClient implements BrowseListener {
void lookForWebServers() {
- myBrowser = DNSSD.browse("_http_.tcp", this);
+ myBrowser = DNSSD.browse("_http._tcp", this);
}
- public void serviceFound(DNSSDService browser, int flags, int ifIndex,
+ public void serviceFound(DNSSDService browser, int flags, int ifIndex,
String serviceName, String regType, String domain) {}
- ...
+ ...
}</CODE></PRE>
<CODE>MyClient.serviceFound()</CODE> would be called for every HTTP server discovered in the
default browse domain(s).
queued. Applications should not update their UI to display browse
results if the MORE_COMING flag is set; they will be called at least once
more with the flag clear.
- */
+ */
public static final int MORE_COMING = ( 1 << 0 );
/** If flag is set in a {@link DomainListener} callback, indicates that the result is the default domain. */
public static final int DEFAULT = ( 1 << 2 );
- /** If flag is set, a name conflict will trigger an exception when registering non-shared records.<P>
- A name must be explicitly specified when registering a service if this bit is set
+ /** If flag is set, a name conflict will trigger an exception when registering non-shared records.<P>
+ A name must be explicitly specified when registering a service if this bit is set
(i.e. the default name may not not be used).
*/
public static final int NO_AUTO_RENAME = ( 1 << 3 );
/** Pass for ifIndex to specify the localhost interface. */
public static final int LOCALHOST_ONLY = -1;
- /** Browse for instances of a service.<P>
+ /** Browse for instances of a service.<P>
Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.<P>
interfaces. Pass -1 to only browse for services provided on the local host.
<P>
@param regType
- The registration type being browsed for followed by the protocol, separated by a
+ The registration type being browsed for followed by the protocol, separated by a
dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
<P>
@param domain
If non-null, specifies the domain on which to browse for services.
- Most applications will not specify a domain, instead browsing on the
+ Most applications will not specify a domain, instead browsing on the
default domain(s).
<P>
@param listener
throws DNSSDException
{ return getInstance()._makeBrowser( flags, ifIndex, regType, domain, listener); }
- /** Browse for instances of a service. Use default flags, ifIndex and domain.<P>
+ /** Browse for instances of a service. Use default flags, ifIndex and domain.<P>
@param regType
- The registration type being browsed for followed by the protocol, separated by a
+ The registration type being browsed for followed by the protocol, separated by a
dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
<P>
@param listener
throws DNSSDException
{ return browse( 0, 0, regType, "", listener); }
- /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.<P>
+ /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.<P>
- Note: Applications should NOT use resolve() solely for txt record monitoring - use
+ Note: Applications should NOT use resolve() solely for txt record monitoring - use
queryRecord() instead, as it is more efficient for this task.<P>
- Note: When the desired results have been returned, the client MUST terminate the resolve by
+ Note: When the desired results have been returned, the client MUST terminate the resolve by
calling {@link DNSSDService#stop}.<P>
Note: resolve() behaves correctly for typical services that have a single SRV record and
- a single TXT record (the TXT record may be empty.) To resolve non-standard services with
+ a single TXT record (the TXT record may be empty.) To resolve non-standard services with
multiple SRV or TXT records, use queryRecord().<P>
@param flags
<P>
@param ifIndex
The interface on which to resolve the service. The client should
- pass the interface on which the serviceName was discovered (i.e.
+ pass the interface on which the serviceName was discovered (i.e.
the ifIndex passed to the serviceFound() callback)
or 0 to resolve the named service on all available interfaces.
<P>
The servicename to be resolved.
<P>
@param regType
- The registration type being resolved followed by the protocol, separated by a
- dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
+ The registration type being resolved followed by the protocol, separated by a
+ dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
<P>
@param domain
The domain on which the service is registered, i.e. the domain passed
@throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
@see RuntimePermission
*/
- public static DNSSDService resolve( int flags, int ifIndex, String serviceName, String regType,
+ public static DNSSDService resolve( int flags, int ifIndex, String serviceName, String regType,
String domain, ResolveListener listener)
throws DNSSDException
{ return getInstance()._resolve( flags, ifIndex, serviceName, regType, domain, listener); }
- /** Register a service, to be discovered via browse() and resolve() calls.<P>
+ /** Register a service, to be discovered via browse() and resolve() calls.<P>
@param flags
Possible values are: NO_AUTO_RENAME.
<P>
@param ifIndex
If non-zero, specifies the interface on which to register the service
(the index for a given interface is determined via the if_nametoindex()
- family of calls.) Most applications will pass 0 to register on all
- available interfaces. Pass -1 to register a service only on the local
+ family of calls.) Most applications will pass 0 to register on all
+ available interfaces. Pass -1 to register a service only on the local
machine (service will not be visible to remote hosts).
<P>
@param serviceName
- If non-null, specifies the service name to be registered.
- Applications need not specify a name, in which case the
- computer name is used (this name is communicated to the client via
+ If non-null, specifies the service name to be registered.
+ Applications need not specify a name, in which case the
+ computer name is used (this name is communicated to the client via
the serviceRegistered() callback).
<P>
@param regType
- The registration type being registered followed by the protocol, separated by a
- dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
+ The registration type being registered followed by the protocol, separated by a
+ dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
<P>
@param domain
If non-null, specifies the domain on which to advertise the service.
- Most applications will not specify a domain, instead automatically
+ Most applications will not specify a domain, instead automatically
registering in the default domain(s).
<P>
@param host
If non-null, specifies the SRV target host name. Most applications
will not specify a host, instead automatically using the machine's
- default host name(s). Note that specifying a non-null host does NOT
- create an address record for that host - the application is responsible
+ default host name(s). Note that specifying a non-null host does NOT
+ create an address record for that host - the application is responsible
for ensuring that the appropriate address record exists, or creating it
via {@link DNSSDRegistration#addRecord}.
<P>
@param port
- The port on which the service accepts connections. Pass 0 for a
- "placeholder" service (i.e. a service that will not be discovered by
- browsing, but will cause a name conflict if another client tries to
+ The port on which the service accepts connections. Pass 0 for a
+ "placeholder" service (i.e. a service that will not be discovered by
+ browsing, but will cause a name conflict if another client tries to
register that same name.) Most clients will not use placeholder services.
<P>
@param txtRecord
- The txt record rdata. May be null. Note that a non-null txtRecord
- MUST be a properly formatted DNS TXT record, i.e. <length byte> <data>
+ The txt record rdata. May be null. Note that a non-null txtRecord
+ MUST be a properly formatted DNS TXT record, i.e. <length byte> <data>
<length byte> <data> ...
<P>
@param listener
@throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
@see RuntimePermission
*/
- public static DNSSDRegistration register( int flags, int ifIndex, String serviceName, String regType,
+ public static DNSSDRegistration register( int flags, int ifIndex, String serviceName, String regType,
String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener)
throws DNSSDException
{ return getInstance()._register( flags, ifIndex, serviceName, regType, domain, host, port, txtRecord, listener); }
- /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.<P>
+ /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.<P>
@param serviceName
- If non-null, specifies the service name to be registered.
- Applications need not specify a name, in which case the
- computer name is used (this name is communicated to the client via
+ If non-null, specifies the service name to be registered.
+ Applications need not specify a name, in which case the
+ computer name is used (this name is communicated to the client via
the serviceRegistered() callback).
<P>
@param regType
- The registration type being registered followed by the protocol, separated by a
- dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
+ The registration type being registered followed by the protocol, separated by a
+ dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
<P>
@param port
- The port on which the service accepts connections. Pass 0 for a
- "placeholder" service (i.e. a service that will not be discovered by
- browsing, but will cause a name conflict if another client tries to
+ The port on which the service accepts connections. Pass 0 for a
+ "placeholder" service (i.e. a service that will not be discovered by
+ browsing, but will cause a name conflict if another client tries to
register that same name.) Most clients will not use placeholder services.
<P>
@param listener
throws DNSSDException
{ return register( 0, 0, serviceName, regType, null, null, port, null, listener); }
- /** Query for an arbitrary DNS record.<P>
+ /** Create a {@link DNSSDRecordRegistrar} allowing efficient registration of
+ multiple individual records.<P>
+ <P>
+ @return A {@link DNSSDRecordRegistrar} that can be used to register records.
+
+ @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
+ @see RuntimePermission
+ */
+ public static DNSSDRecordRegistrar createRecordRegistrar( RegisterRecordListener listener)
+ throws DNSSDException
+ { return getInstance()._createRecordRegistrar( listener); }
+
+ /** Query for an arbitrary DNS record.<P>
@param flags
Possible values are: MORE_COMING.
<P>
@param ifIndex
If non-zero, specifies the interface on which to issue the query
(the index for a given interface is determined via the if_nametoindex()
- family of calls.) Passing 0 causes the name to be queried for on all
+ family of calls.) Passing 0 causes the name to be queried for on all
interfaces. Passing -1 causes the name to be queried for only on the
local host.
<P>
as defined in nameser.h.
<P>
@param rrclass
- The class of the resource record, as defined in nameser.h
+ The class of the resource record, as defined in nameser.h
(usually 1 for the Internet class).
<P>
@param listener
@throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
@see RuntimePermission
*/
- public static DNSSDService queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
+ public static DNSSDService queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
int rrclass, QueryListener listener)
throws DNSSDException
{ return getInstance()._queryRecord( flags, ifIndex, serviceName, rrtype, rrclass, listener); }
- /** Asynchronously enumerate domains available for browsing and registration.<P>
+ /** Asynchronously enumerate domains available for browsing and registration.<P>
Currently, the only domain returned is "local.", but other domains will be returned in future.<P>
@param ifIndex
If non-zero, specifies the interface on which to look for domains.
(the index for a given interface is determined via the if_nametoindex()
- family of calls.) Most applications will pass 0 to enumerate domains on
- all interfaces.
+ family of calls.) Most applications will pass 0 to enumerate domains on
+ all interfaces.
<P>
@param listener
This object will get called when domains are found.
throws DNSSDException
{ return getInstance()._enumerateDomains( flags, ifIndex, listener); }
- /** Concatenate a three-part domain name (as provided to the listeners) into a
- properly-escaped full domain name. Note that strings passed to listeners are
- ALREADY ESCAPED where necessary.<P>
+ /** Concatenate a three-part domain name (as provided to the listeners) into a
+ properly-escaped full domain name. Note that strings passed to listeners are
+ ALREADY ESCAPED where necessary.<P>
@param serviceName
The service name - any dots or slashes must NOT be escaped.
May be null (to construct a PTR record name, e.g. "_ftp._tcp.apple.com").
<P>
@param regType
- The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").
+ The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").
<P>
@param domain
The domain name, e.g. "apple.com". Any literal dots or backslashes must be escaped.
throws DNSSDException
{ return getInstance()._constructFullName( serviceName, regType, domain); }
- /** Instruct the daemon to verify the validity of a resource record that appears to
- be out of date. (e.g. because tcp connection to a service's target failed.) <P>
+ /** Instruct the daemon to verify the validity of a resource record that appears to
+ be out of date. (e.g. because tcp connection to a service's target failed.) <P>
- Causes the record to be flushed from the daemon's cache (as well as all other
+ Causes the record to be flushed from the daemon's cache (as well as all other
daemons' caches on the network) if the record is determined to be invalid.<P>
@param flags
Currently unused, reserved for future use.
@param ifIndex
If non-zero, specifies the interface on which to reconfirm the record
(the index for a given interface is determined via the if_nametoindex()
- family of calls.) Passing 0 causes the name to be reconfirmed on all
+ family of calls.) Passing 0 causes the name to be reconfirmed on all
interfaces. Passing -1 causes the name to be reconfirmed only on the
local host.
<P>
@throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
@see RuntimePermission
*/
- public static void reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
+ public static void reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
int rrclass, byte[] rdata)
{ getInstance()._reconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata); }
- /** Return the canonical name of a particular interface index.<P>
+ /** Return the canonical name of a particular interface index.<P>
@param ifIndex
A valid interface index. Must not be ALL_INTERFACES.
<P>
public static String getNameForIfIndex( int ifIndex)
{ return getInstance()._getNameForIfIndex( ifIndex); }
- /** Return the index of a named interface.<P>
+ /** Return the index of a named interface.<P>
@param ifName
A valid interface name. An example is java.net.NetworkInterface.getName().
<P>
protected DNSSD() {} // prevent direct instantiation
/** Return the single instance of DNSSD. */
- static protected final DNSSD getInstance()
+ static protected final DNSSD getInstance()
{
SecurityManager sm = System.getSecurityManager();
- if ( sm != null)
- sm.checkPermission( new RuntimePermission( "getDNSSDInstance"));
- return fInstance;
+ if ( sm != null)
+ sm.checkPermission( new RuntimePermission( "getDNSSDInstance"));
+ return fInstance;
}
abstract protected DNSSDService _makeBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener listener)
throws DNSSDException;
- abstract protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
+ abstract protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
String domain, ResolveListener listener)
throws DNSSDException;
- abstract protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType,
+ abstract protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType,
String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener)
throws DNSSDException;
- abstract protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
+ abstract protected DNSSDRecordRegistrar _createRecordRegistrar( RegisterRecordListener listener)
+ throws DNSSDException;
+
+ abstract protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
int rrclass, QueryListener listener)
throws DNSSDException;
abstract protected String _constructFullName( String serviceName, String regType, String domain)
throws DNSSDException;
- abstract protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
+ abstract protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
int rrclass, byte[] rdata);
abstract protected String _getNameForIfIndex( int ifIndex);
static
{
try
- {
+ {
String name = System.getProperty( "com.apple.dnssd.DNSSD" );
if( name == null )
name = "com.apple.dnssd.AppleDNSSD"; // Fall back to Apple-provided class.
"BADTIME",
"BADSIG",
"BADKEY",
- "TRANSIENT"
+ "TRANSIENT",
+ "SERVICENOTRUNNING",
+ "NATPORTMAPPINGUNSUPPORTED",
+ "NATPORTMAPPINGDISABLED"
};
if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
{
System.loadLibrary( "jdns_sd");
- int libInitResult = InitLibrary( 1);
+ int libInitResult = InitLibrary( 2); // Current version number (must be sync'd with jnilib version)
if ( libInitResult != DNSSDException.NO_ERROR)
throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage());
return new AppleBrowser( flags, ifIndex, regType, domain, client);
}
- protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
+ protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
String domain, ResolveListener client)
throws DNSSDException
{
return new AppleResolver( flags, ifIndex, serviceName, regType, domain, client);
}
- protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType,
+ protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType,
String domain, String host, int port, TXTRecord txtRecord, RegisterListener client)
throws DNSSDException
{
- return new AppleRegistration( flags, ifIndex, serviceName, regType, domain, host, port,
+ return new AppleRegistration( flags, ifIndex, serviceName, regType, domain, host, port,
( txtRecord != null) ? txtRecord.getRawBytes() : null, client);
}
- protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
+ protected DNSSDRecordRegistrar _createRecordRegistrar( RegisterRecordListener listener)
+ throws DNSSDException
+ {
+ return new AppleRecordRegistrar( listener);
+ }
+
+ protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
int rrclass, QueryListener client)
throws DNSSDException
{
return responseHolder[0];
}
- protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
+ protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
int rrclass, byte[] rdata)
{
ReconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata);
protected native int ConstructName( String serviceName, String regType, String domain, String[] pOut);
- protected native void ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
+ protected native void ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
int rrclass, byte[] rdata);
protected native String GetNameForIfIndex( int ifIndex);
throw new AppleDNSSDException( rc);
}
- protected int /* warning */ fNativeContext; // Private storage for native side
+ protected long /* warning */ fNativeContext; // Private storage for native side
public void run()
{
class AppleBrowser extends AppleService
{
- public AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client)
+ public AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client)
throws DNSSDException
- {
+ {
super(client);
this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain));
if ( !AppleDNSSD.hasAutoCallbacks)
class AppleResolver extends AppleService
{
- public AppleResolver( int flags, int ifIndex, String serviceName, String regType,
- String domain, ResolveListener client)
+ public AppleResolver( int flags, int ifIndex, String serviceName, String regType,
+ String domain, ResolveListener client)
throws DNSSDException
- {
- super(client);
+ {
+ super(client);
this.ThrowOnErr( this.CreateResolver( flags, ifIndex, serviceName, regType, domain));
if ( !AppleDNSSD.hasAutoCallbacks)
new Thread(this).start();
}
// Sets fNativeContext. Returns non-zero on error.
- protected native int CreateResolver( int flags, int ifIndex, String serviceName, String regType,
+ protected native int CreateResolver( int flags, int ifIndex, String serviceName, String regType,
String domain);
}
// An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
class AppleDNSRecord implements DNSRecord
{
- public AppleDNSRecord( AppleService owner)
- {
- fOwner = owner;
+ public AppleDNSRecord( AppleService owner)
+ {
+ fOwner = owner;
fRecord = 0; // record always starts out empty
}
this.ThrowOnErr( this.Remove());
}
- protected int fRecord; // Really a DNSRecord; sizeof(int) == sizeof(void*) ?
+ protected long fRecord; // Really a DNSRecord; sizeof(long) == sizeof(void*) ?
protected AppleService fOwner;
protected void ThrowOnErr( int rc) throws DNSSDException
class AppleRegistration extends AppleService implements DNSSDRegistration
{
- public AppleRegistration( int flags, int ifIndex, String serviceName, String regType, String domain,
- String host, int port, byte[] txtRecord, RegisterListener client)
+ public AppleRegistration( int flags, int ifIndex, String serviceName, String regType, String domain,
+ String host, int port, byte[] txtRecord, RegisterListener client)
throws DNSSDException
- {
- super(client);
+ {
+ super(client);
this.ThrowOnErr( this.BeginRegister( ifIndex, flags, serviceName, regType, domain, host, port, txtRecord));
if ( !AppleDNSSD.hasAutoCallbacks)
new Thread(this).start();
AppleDNSRecord newRecord = new AppleDNSRecord( this);
this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
-
return newRecord;
}
}
// Sets fNativeContext. Returns non-zero on error.
- protected native int BeginRegister( int ifIndex, int flags, String serviceName, String regType,
+ protected native int BeginRegister( int ifIndex, int flags, String serviceName, String regType,
String domain, String host, int port, byte[] txtRecord);
// Sets fNativeContext. Returns non-zero on error.
protected native int AddRecord( int flags, int rrType, byte[] rData, int ttl, AppleDNSRecord destObj);
}
+class AppleRecordRegistrar extends AppleService implements DNSSDRecordRegistrar
+{
+ public AppleRecordRegistrar( RegisterRecordListener listener)
+ throws DNSSDException
+ {
+ super(listener);
+ this.ThrowOnErr( this.CreateConnection());
+ if ( !AppleDNSSD.hasAutoCallbacks)
+ new Thread(this).start();
+ }
+
+ public DNSRecord registerRecord( int flags, int ifIndex, String fullname, int rrtype,
+ int rrclass, byte[] rdata, int ttl)
+ throws DNSSDException
+ {
+ AppleDNSRecord newRecord = new AppleDNSRecord( this);
+
+ this.ThrowOnErr( this.RegisterRecord( flags, ifIndex, fullname, rrtype, rrclass, rdata, ttl, newRecord));
+ return newRecord;
+ }
+
+ // Sets fNativeContext. Returns non-zero on error.
+ protected native int CreateConnection();
+
+ // Sets fNativeContext. Returns non-zero on error.
+ protected native int RegisterRecord( int flags, int ifIndex, String fullname, int rrtype,
+ int rrclass, byte[] rdata, int ttl, AppleDNSRecord destObj);
+}
+
class AppleQuery extends AppleService
{
- public AppleQuery( int flags, int ifIndex, String serviceName, int rrtype,
- int rrclass, QueryListener client)
+ public AppleQuery( int flags, int ifIndex, String serviceName, int rrtype,
+ int rrclass, QueryListener client)
throws DNSSDException
- {
- super(client);
+ {
+ super(client);
this.ThrowOnErr( this.CreateQuery( flags, ifIndex, serviceName, rrtype, rrclass));
if ( !AppleDNSSD.hasAutoCallbacks)
new Thread(this).start();
class AppleDomainEnum extends AppleService
{
- public AppleDomainEnum( int flags, int ifIndex, DomainListener client)
+ public AppleDomainEnum( int flags, int ifIndex, DomainListener client)
throws DNSSDException
- {
- super(client);
+ {
+ super(client);
this.ThrowOnErr( this.BeginEnum( flags, ifIndex));
if ( !AppleDNSSD.hasAutoCallbacks)
new Thread(this).start();
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSSDException.java,v $
+Revision 1.6 2007/02/08 23:58:17 cheshire
+Added comment about updating kMessages array in AppleDNSSDException (DNSSD.java)
+
+Revision 1.5 2007/02/07 01:19:36 cheshire
+<rdar://problem/4849427> API: Reconcile conflicting error code values
+
+Revision 1.4 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/07/10 22:19:01 cheshire
Add missing error codes to list of public static final ints
abstract public class DNSSDException extends Exception
{
- public static final int NO_ERROR = 0;
- public static final int UNKNOWN = -65537;
- public static final int NO_SUCH_NAME = -65538;
- public static final int NO_MEMORY = -65539;
- public static final int BAD_PARAM = -65540;
- public static final int BAD_REFERENCE = -65541;
- public static final int BAD_STATE = -65542;
- public static final int BAD_FLAGS = -65543;
- public static final int UNSUPPORTED = -65544;
- public static final int NOT_INITIALIZED = -65545;
- public static final int NO_CACHE = -65546;
- public static final int ALREADY_REGISTERED = -65547;
- public static final int NAME_CONFLICT = -65548;
- public static final int INVALID = -65549;
- public static final int FIREWALL = -65550;
- public static final int INCOMPATIBLE = -65551;
- public static final int BAD_INTERFACE_INDEX = -65552;
- public static final int REFUSED = -65553;
- public static final int NOSUCHRECORD = -65554;
- public static final int NOAUTH = -65555;
- public static final int NOSUCHKEY = -65556;
- public static final int NATTRAVERSAL = -65557;
- public static final int DOUBLENAT = -65558;
- public static final int BADTIME = -65559;
- public static final int BADSIG = -65560;
- public static final int BADKEY = -65561;
- public static final int TRANSIENT = -65562;
+ public static final int NO_ERROR = 0;
+ public static final int UNKNOWN = -65537;
+ public static final int NO_SUCH_NAME = -65538;
+ public static final int NO_MEMORY = -65539;
+ public static final int BAD_PARAM = -65540;
+ public static final int BAD_REFERENCE = -65541;
+ public static final int BAD_STATE = -65542;
+ public static final int BAD_FLAGS = -65543;
+ public static final int UNSUPPORTED = -65544;
+ public static final int NOT_INITIALIZED = -65545;
+ public static final int NO_CACHE = -65546;
+ public static final int ALREADY_REGISTERED = -65547;
+ public static final int NAME_CONFLICT = -65548;
+ public static final int INVALID = -65549;
+ public static final int FIREWALL = -65550;
+ public static final int INCOMPATIBLE = -65551;
+ public static final int BAD_INTERFACE_INDEX = -65552;
+ public static final int REFUSED = -65553;
+ public static final int NOSUCHRECORD = -65554;
+ public static final int NOAUTH = -65555;
+ public static final int NOSUCHKEY = -65556;
+ public static final int NATTRAVERSAL = -65557;
+ public static final int DOUBLENAT = -65558;
+ public static final int BADTIME = -65559;
+ public static final int BADSIG = -65560;
+ public static final int BADKEY = -65561;
+ public static final int TRANSIENT = -65562;
+ public static final int SERVICENOTRUNNING = -65563;
+ public static final int NATPORTMAPPINGUNSUPPORTED = -65564;
+ public static final int NATPORTMAPPINGDISABLED = -65565;
+
+ // Note: When adding new error values here, remember also
+ // to update the corresponding kMessages array in AppleDNSSDException (DNSSD.java)
/** Returns the sub-code that identifies the particular error. */
abstract public int getErrorCode();
--- /dev/null
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ This file declares the public interface to DNSSDRecordRegistrar, a DNSSDService
+ subclass that allows efficient registration of multiple individual records.
+
+ Change History (most recent first):
+
+$Log: DNSSDRecordRegistrar.java,v $
+Revision 1.2 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.1 2006/06/20 23:00:12 rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
+ */
+
+
+package com.apple.dnssd;
+
+
+/** An object for registering records, created by {@link DNSSD#createRecordRegistrar}. */
+
+public interface DNSSDRecordRegistrar extends DNSSDService
+{
+ /** Register an independent {@link DNSRecord}.<P>
+ @param flags
+ Possible values are SHARED or UNIQUE (see flag type definitions for details).
+ <P>
+ @param ifIndex
+ If non-zero, specifies the interface on which to register the record
+ (the index for a given interface is determined via the if_nametoindex()
+ family of calls.) Passing 0 causes the record to be registered on all interfaces.
+ <P>
+ @param fullname
+ The full domain name of the resource record.
+ <P>
+ @param rrtype
+ The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
+ as defined in nameser.h.
+ <P>
+ @param rrclass
+ The class of the resource record, as defined in nameser.h
+ (usually 1 for the Internet class).
+ <P>
+ @param rData
+ The new rdata as it is to appear in the DNS record.
+ <P>
+ @param ttl
+ The time to live of the resource record, in seconds. Pass 0 to use a default value.
+ <P>
+ @param listener
+ This object will get called when the service is registered.
+ <P>
+ @return A {@link DNSSDService} that can be used to abort the record registration.
+
+ @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
+ @see RuntimePermission
+ */
+ public DNSRecord registerRecord( int flags, int ifIndex, String fullname, int rrtype,
+ int rrclass, byte[] rdata, int ttl)
+ throws DNSSDException;
+}
+
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSSDRegistration.java,v $
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/12/11 03:01:00 rpantos
<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DNSSDService.java,v $
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/04/30 21:48:27 rpantos
Change line endings for CVS.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: DomainListener.java,v $
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/04/30 21:48:27 rpantos
Change line endings for CVS.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: JNISupport.c,v $
+Revision 1.21 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.20 2007/03/13 01:41:46 cheshire
+Fixed compile warnings when building 32-bit
+
+Revision 1.19 2007/03/13 00:28:03 vazquez
+<rdar://problem/4625928> Java: Rename exported symbols in libjdns_sd.jnilib
+
+Revision 1.18 2007/03/13 00:10:14 vazquez
+<rdar://problem/4455206> Java: 64 bit JNI patch
+
+Revision 1.17 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.16 2006/07/14 02:35:47 cheshire
+Added (commented out) syslog debugging messages
+
+Revision 1.15 2006/06/27 19:34:43 cheshire
+<rdar://problem/4430023> txtRecord parameter of DNSServiceResolveReply() should be unsigned char *
+
+Revision 1.14 2006/06/20 23:03:35 rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
Revision 1.13 2005/10/26 01:52:24 cheshire
<rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
#include "DNSSD.java.h"
+//#include <syslog.h>
+
// convenience definition
#ifdef __GNUC__
#define _UNUSED __attribute__ ((unused))
#endif
enum {
- kInterfaceVersion = 1 // Must match version in .jar file
+ kInterfaceVersionOne = 1,
+ kInterfaceVersionCurrent // Must match version in .jar file
};
typedef struct OpContext OpContext;
jint callerVersion)
{
/* Ensure that caller & interface versions match. */
- if ( callerVersion != kInterfaceVersion)
+ if ( callerVersion != kInterfaceVersionCurrent)
return kDNSServiceErr_Incompatible;
#if AUTO_CALLBACKS
/* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
{
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
if ( contextField != 0)
{
- OpContext *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+ OpContext *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
if ( pContext != NULL)
{
// MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
- (*pEnv)->SetIntField( pEnv, pThis, contextField, 0);
+ (*pEnv)->SetLongField(pEnv, pThis, contextField, 0);
if ( pContext->ServiceRef != NULL)
DNSServiceRefDeallocate( pContext->ServiceRef);
// BlockForData() not supported with AUTO_CALLBACKS
#if !AUTO_CALLBACKS
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
if ( contextField != 0)
{
- OpContext *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+ OpContext *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
if ( pContext != NULL)
{
fd_set readFDs;
#if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
- OpContext *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
+ OpContext *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
DNSServiceErrorType err = kDNSServiceErr_BadState;
if ( pContext != NULL)
jint flags, jint ifIndex, jstring regType, jstring domain)
{
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
OpContext *pContext = NULL;
DNSServiceErrorType err = kDNSServiceErr_NoError;
err = DNSServiceBrowse( &pContext->ServiceRef, flags, ifIndex, regStr, domainStr, ServiceBrowseReply, pContext);
if ( err == kDNSServiceErr_NoError)
{
- (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+ (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
}
SafeReleaseUTFChars( pEnv, regType, regStr);
static void DNSSD_API ServiceResolveReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget,
- uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
+ uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context)
{
OpContext *pContext = (OpContext*) context;
jclass txtCls;
jint flags, jint ifIndex, jstring serviceName, jstring regType, jstring domain)
{
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
OpContext *pContext = NULL;
DNSServiceErrorType err = kDNSServiceErr_NoError;
servStr, regStr, domainStr, ServiceResolveReply, pContext);
if ( err == kDNSServiceErr_NoError)
{
- (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+ (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
}
SafeReleaseUTFChars( pEnv, serviceName, servStr);
jint ifIndex, jint flags, jstring serviceName, jstring regType,
jstring domain, jstring host, jint port, jbyteArray txtRecord)
{
+ //syslog(LOG_ERR, "BR");
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
OpContext *pContext = NULL;
DNSServiceErrorType err = kDNSServiceErr_NoError;
jbyte *pBytes;
jsize numBytes;
+ //syslog(LOG_ERR, "BR: contextField %d", contextField);
+
if ( contextField != 0)
pContext = NewContext( pEnv, pThis, "serviceRegistered",
"(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
const char *domainStr = SafeGetUTFChars( pEnv, domain);
const char *hostStr = SafeGetUTFChars( pEnv, host);
+ //syslog(LOG_ERR, "BR: regStr %s", regStr);
+
// Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
// big-endian number into a 16-bit pattern here.
uint16_t portBits = port;
numBytes, pBytes, ServiceRegisterReply, pContext);
if ( err == kDNSServiceErr_NoError)
{
- (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+ (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
}
if ( pBytes != NULL)
jint flags, jint rrType, jbyteArray rData, jint ttl, jobject destObj)
{
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
jclass destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
- jfieldID recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "I");
+ jfieldID recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "J");
OpContext *pContext = NULL;
DNSServiceErrorType err = kDNSServiceErr_NoError;
jbyte *pBytes;
DNSRecordRef recRef;
if ( contextField != 0)
- pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
+ pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
if ( pContext == NULL || pContext->ServiceRef == NULL)
return kDNSServiceErr_BadParam;
err = DNSServiceAddRecord( pContext->ServiceRef, &recRef, flags, rrType, numBytes, pBytes, ttl);
if ( err == kDNSServiceErr_NoError)
{
- (*pEnv)->SetIntField( pEnv, destObj, recField, (jint) recRef);
+ (*pEnv)->SetLongField(pEnv, destObj, recField, (long) recRef);
}
if ( pBytes != NULL)
{
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
jfieldID ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
- jfieldID recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
+ jfieldID recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "J");
OpContext *pContext = NULL;
DNSServiceErrorType err = kDNSServiceErr_NoError;
jbyte *pBytes;
{
jobject ownerObj = (*pEnv)->GetObjectField( pEnv, pThis, ownerField);
jclass ownerClass = (*pEnv)->GetObjectClass( pEnv, ownerObj);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "J");
if ( contextField != 0)
- pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, ownerObj, contextField);
+ pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, ownerObj, contextField);
}
if ( recField != 0)
- recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
+ recRef = (DNSRecordRef) (long) (*pEnv)->GetLongField(pEnv, pThis, recField);
if ( pContext == NULL || pContext->ServiceRef == NULL)
return kDNSServiceErr_BadParam;
{
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
jfieldID ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
- jfieldID recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
+ jfieldID recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "J");
OpContext *pContext = NULL;
DNSServiceErrorType err = kDNSServiceErr_NoError;
DNSRecordRef recRef = NULL;
{
jobject ownerObj = (*pEnv)->GetObjectField( pEnv, pThis, ownerField);
jclass ownerClass = (*pEnv)->GetObjectClass( pEnv, ownerObj);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "J");
if ( contextField != 0)
- pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, ownerObj, contextField);
+ pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, ownerObj, contextField);
}
if ( recField != 0)
- recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
+ recRef = (DNSRecordRef) (long) (*pEnv)->GetLongField(pEnv, pThis, recField);
if ( pContext == NULL || pContext->ServiceRef == NULL)
return kDNSServiceErr_BadParam;
}
+JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv *pEnv, jobject pThis)
+{
+ jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
+ OpContext *pContext = NULL;
+ DNSServiceErrorType err = kDNSServiceErr_NoError;
+
+ if ( contextField != 0)
+ pContext = NewContext( pEnv, pThis, "recordRegistered", "(Lcom/apple/dnssd/DNSRecord;I)V");
+ else
+ err = kDNSServiceErr_BadParam;
+
+ if ( pContext != NULL)
+ {
+ err = DNSServiceCreateConnection( &pContext->ServiceRef);
+ if ( err == kDNSServiceErr_NoError)
+ {
+ (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
+ }
+ }
+ else
+ err = kDNSServiceErr_NoMemory;
+
+ return err;
+}
+
+struct RecordRegistrationRef
+{
+ OpContext *Context;
+ jobject RecordObj;
+};
+typedef struct RecordRegistrationRef RecordRegistrationRef;
+
+static void DNSSD_API RegisterRecordReply( DNSServiceRef sdRef _UNUSED,
+ DNSRecordRef recordRef _UNUSED, DNSServiceFlags flags,
+ DNSServiceErrorType errorCode, void *context)
+{
+ RecordRegistrationRef *regEnvelope = (RecordRegistrationRef*) context;
+ OpContext *pContext = regEnvelope->Context;
+
+ SetupCallbackState( &pContext->Env);
+
+ if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
+ {
+ if ( errorCode == kDNSServiceErr_NoError)
+ {
+ (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj, pContext->Callback,
+ regEnvelope->RecordObj, flags);
+ }
+ else
+ ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
+ }
+
+ (*pContext->Env)->DeleteWeakGlobalRef( pContext->Env, regEnvelope->RecordObj);
+ free( regEnvelope);
+
+ TeardownCallbackState();
+}
+
+JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRecordRegistrar_RegisterRecord( JNIEnv *pEnv, jobject pThis,
+ jint flags, jint ifIndex, jstring fullname, jint rrType, jint rrClass,
+ jbyteArray rData, jint ttl, jobject destObj)
+{
+ jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
+ jclass destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
+ jfieldID recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "J");
+ const char *nameStr = SafeGetUTFChars( pEnv, fullname);
+ OpContext *pContext = NULL;
+ DNSServiceErrorType err = kDNSServiceErr_NoError;
+ jbyte *pBytes;
+ jsize numBytes;
+ DNSRecordRef recRef;
+ RecordRegistrationRef *regEnvelope;
+
+ if ( contextField != 0)
+ pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
+ if ( pContext == NULL || pContext->ServiceRef == NULL || nameStr == NULL)
+ return kDNSServiceErr_BadParam;
+
+ regEnvelope = calloc( 1, sizeof *regEnvelope);
+ if ( regEnvelope == NULL)
+ return kDNSServiceErr_NoMemory;
+ regEnvelope->Context = pContext;
+ regEnvelope->RecordObj = (*pEnv)->NewWeakGlobalRef( pEnv, destObj); // must convert local ref to global to cache
+
+ pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
+ numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
+
+ err = DNSServiceRegisterRecord( pContext->ServiceRef, &recRef, flags, ifIndex,
+ nameStr, rrType, rrClass, numBytes, pBytes, ttl,
+ RegisterRecordReply, regEnvelope);
+
+ if ( err == kDNSServiceErr_NoError)
+ {
+ (*pEnv)->SetLongField(pEnv, destObj, recField, (long) recRef);
+ }
+ else
+ {
+ if ( regEnvelope->RecordObj != NULL)
+ (*pEnv)->DeleteWeakGlobalRef( pEnv, regEnvelope->RecordObj);
+ free( regEnvelope);
+ }
+
+ if ( pBytes != NULL)
+ (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
+
+ SafeReleaseUTFChars( pEnv, fullname, nameStr);
+
+ return err;
+}
+
+
static void DNSSD_API ServiceQueryReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *serviceName,
uint16_t rrtype, uint16_t rrclass, uint16_t rdlen,
jint flags, jint ifIndex, jstring serviceName, jint rrtype, jint rrclass)
{
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
OpContext *pContext = NULL;
DNSServiceErrorType err = kDNSServiceErr_NoError;
rrtype, rrclass, ServiceQueryReply, pContext);
if ( err == kDNSServiceErr_NoError)
{
- (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+ (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
}
SafeReleaseUTFChars( pEnv, serviceName, servStr);
jint flags, jint ifIndex)
{
jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
- jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
+ jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
OpContext *pContext = NULL;
DNSServiceErrorType err = kDNSServiceErr_NoError;
DomainEnumReply, pContext);
if ( err == kDNSServiceErr_NoError)
{
- (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
+ (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
}
}
else
{
char *p = LOCAL_ONLY_NAME, nameBuff[IF_NAMESIZE];
- if (ifIndex != kDNSServiceInterfaceIndexLocalOnly)
+ if (ifIndex != (jint) kDNSServiceInterfaceIndexLocalOnly)
p = if_indextoname( ifIndex, nameBuff );
return (*pEnv)->NewStringUTF( pEnv, p);
return ifIndex;
}
#endif
+
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: QueryListener.java,v $
+Revision 1.4 2007/03/12 23:43:08 vazquez
+<rdar://problem/4169128> Documentation: Error in Java queryAnswered doc
+
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/04/30 21:48:27 rpantos
Change line endings for CVS.
public interface QueryListener extends BaseListener
{
- /** Called when a record query has been completed.<P>
+ /** Called when a record query has been completed. Inspect flags
+ parameter to determine nature of query event.<P>
@param query
The active query object.
<P>
@param flags
- Possible values are DNSSD.MORE_COMING.
+ If kDNSServiceFlagsAdd bit is set, this is a newly discovered answer;
+ otherwise this is a previously discovered answer which has expired.
+ Other possible values are DNSSD.MORE_COMING.
<P>
@param ifIndex
The interface on which the query was resolved. (The index for a given
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: RegisterListener.java,v $
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/04/30 21:48:27 rpantos
Change line endings for CVS.
--- /dev/null
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: RegisterRecordListener.java,v $
+Revision 1.2 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.1 2006/06/20 23:00:12 rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
+
+ */
+
+
+package com.apple.dnssd;
+
+
+/** A listener that receives results from {@link DNSSDRecordRegistrar#registerRecord}. */
+
+public interface RegisterRecordListener extends BaseListener
+{
+ /** Called when a record registration succeeds.<P>
+
+ @param record
+ A {@link DNSRecord}.
+ <P>
+ @param flags
+ Currently ignored, reserved for future use.
+ <P>
+ */
+ void recordRegistered( DNSRecord record, int flags);
+}
+
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ResolveListener.java,v $
+Revision 1.3 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/04/30 21:48:27 rpantos
Change line endings for CVS.
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: TXTRecord.java,v $
+Revision 1.8 2007/03/16 23:39:40 vazquez
+<rdar://problem/4612778> Java: Coding error in java wrappers, limited TXTRecord length
+
+Revision 1.7 2006/12/13 07:13:23 mkrochma
+<rdar://problem/4612778> Java: Coding error in java wrappers, limited TXTRecord length
+
+Revision 1.6 2006/08/14 23:25:08 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.5 2004/08/25 21:54:36 rpantos
<rdar://problem/3773973> Fix getValue() for values containing '='.
byte[] oldBytes = fBytes;
int valLen = (value != null) ? value.length : 0;
int insertion = 0;
- byte newLen, avLen;
+ int newLen, avLen;
// locate the insertion point
for ( int i=0; i < index && insertion < fBytes.length; i++)
- insertion += fBytes[ insertion] + 1;
+ insertion += (0xFF & (fBytes[ insertion] + 1));
- avLen = (byte) ( keyBytes.length + valLen + (value != null ? 1 : 0));
- newLen = (byte) ( avLen + oldBytes.length + 1);
+ avLen = keyBytes.length + valLen + (value != null ? 1 : 0);
+ newLen = avLen + oldBytes.length + 1;
fBytes = new byte[ newLen];
System.arraycopy( oldBytes, 0, fBytes, 0, insertion);
int secondHalfLen = oldBytes.length - insertion;
System.arraycopy( oldBytes, insertion, fBytes, newLen - secondHalfLen, secondHalfLen);
- fBytes[ insertion] = avLen;
+ fBytes[ insertion] = ( byte) avLen;
System.arraycopy( keyBytes, 0, fBytes, insertion + 1, keyBytes.length);
if ( value != null)
{
return i;
}
}
- avStart += avLen + 1;
+ avStart += (0xFF & (avLen + 1));
}
return -1;
}
int i, avStart;
for ( i=0, avStart=0; avStart < fBytes.length; i++)
- avStart += fBytes[ avStart] + 1;
+ avStart += (0xFF & (fBytes[ avStart] + 1));
return i;
}
*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: PlatformCommon.c,v $
+Revision 1.11 2007/07/31 23:08:34 mcguire
+<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
+
+Revision 1.10 2007/07/11 02:59:58 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add AutoTunnel parameter to mDNS_SetSecretForDomain
+
+Revision 1.9 2007/01/09 22:37:44 cheshire
+Remove unused ClearDomainSecrets() function
+
+Revision 1.8 2006/12/22 20:59:51 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.7 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.6 2005/04/08 21:30:16 ksekar
<rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
Patch submitted by Bernd Kuhls
#include <netinet/in.h> // Needed for sockaddr_in
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
#include "PlatformCommon.h"
#ifdef NOT_HAVE_SOCKLEN_T
typedef unsigned int socklen_t;
#endif
-// Bind a UDP socket to a global destination to find the default route's interface address
-mDNSexport void FindDefaultRouteIP(mDNSAddr *a)
+// Bind a UDP socket to find the source address to a destination
+mDNSexport void FindSourceAddrForIP(mDNSAddr *const dst, mDNSAddr *src)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int sock = socket(AF_INET,SOCK_DGRAM,0);
- a->type = mDNSAddrType_None;
+ src->type = mDNSAddrType_None;
if (sock == -1) return;
+ if (dst->type != mDNSAddrType_IPv4) return; // Only support v4 for now
addr.sin_family = AF_INET;
- addr.sin_port = 1; // Not important, any port and public address will do
- addr.sin_addr.s_addr = 0x11111111;
+ addr.sin_port = 1; // Not important, any port will do
+ if (dst == NULL) addr.sin_addr.s_addr = 0x11111111;
+ else addr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
if ((connect(sock,(const struct sockaddr*)&addr,sizeof(addr))) == -1) { close(sock); return; }
if ((getsockname(sock,(struct sockaddr*)&addr, &len)) == -1) { close(sock); return; }
close(sock);
- a->type = mDNSAddrType_IPv4;
- a->ip.v4.NotAnInteger = addr.sin_addr.s_addr;
+ src->type = mDNSAddrType_IPv4;
+ src->ip.v4.NotAnInteger = addr.sin_addr.s_addr;
}
// dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length
if (domain && domain->c[0] && secret[0])
{
+ DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
// for now we assume keyname = service reg domain and we use same key for service and hostname registration
- err = mDNS_SetSecretForZone(m, domain, domain, secret);
- if (err) LogMsg("ERROR: mDNS_SetSecretForZone returned %d for domain %##s", err, domain->c);
+ err = mDNS_SetSecretForDomain(m, info, domain, domain, secret, mDNSfalse);
+ if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
}
return;
*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: PlatformCommon.h,v $
+Revision 1.7 2007/07/31 23:08:34 mcguire
+<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
+
+Revision 1.6 2007/01/09 22:37:43 cheshire
+Remove unused ClearDomainSecrets() function
+
+Revision 1.5 2006/12/22 20:59:51 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.4 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/01/19 19:19:21 ksekar
<rdar://problem/3960191> Need a way to turn off domain discovery
*/
-extern void FindDefaultRouteIP(mDNSAddr *a);
+extern void FindSourceAddrForIP(mDNSAddr *const dst, mDNSAddr *src);
extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled);
+.\" -*- tab-width: 4 -*-
+.\"
.\" Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
.\"
-.\" @APPLE_LICENSE_HEADER_START@
+.\" Licensed under the Apache License, Version 2.0 (the "License");
+.\" you may not use this file except in compliance with the License.
+.\" You may obtain a copy of the License at
.\"
-.\" This file contains Original Code and/or Modifications of Original Code
-.\" as defined in and that are subject to the Apple Public Source License
-.\" Version 2.0 (the 'License'). You may not use this file except in
-.\" compliance with the License. Please obtain a copy of the License at
-.\" http://www.opensource.apple.com/apsl/ and read it before using this
-.\" file.
+.\" http://www.apache.org/licenses/LICENSE-2.0
.\"
-.\" The Original Code and all software distributed under the License are
-.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-.\" Please see the License for the specific language governing rights and
+.\" Unless required by applicable law or agreed to in writing, software
+.\" distributed under the License is distributed on an "AS IS" BASIS,
+.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+.\" See the License for the specific language governing permissions and
.\" limitations under the License.
-.\"
-.\" @APPLE_LICENSE_HEADER_END@
.\"
.\" $Log: dns-sd.1,v $
+.\" Revision 1.6 2006/08/14 23:24:56 cheshire
+.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+.\"
.\" Revision 1.5 2005/07/04 23:12:35 cheshire
.\" <rdar://problem/4103628> The dns-sd command first appeared in Mac OS X 10.4 (Tiger)
.\"
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+
+/*! @header DNS Service Discovery
+ *
+ * @discussion This section describes the functions, callbacks, and data structures
+ * that make up the DNS Service Discovery API.
+ *
+ * The DNS Service Discovery API is part of Bonjour, Apple's implementation
+ * of zero-configuration networking (ZEROCONF).
+ *
+ * Bonjour allows you to register a network service, such as a
+ * printer or file server, so that it can be found by name or browsed
+ * for by service type and domain. Using Bonjour, applications can
+ * discover what services are available on the network, along with
+ * all the information -- such as name, IP address, and port --
+ * necessary to access a particular service.
+ *
+ * In effect, Bonjour combines the functions of a local DNS server and
+ * AppleTalk. Bonjour allows applications to provide user-friendly printer
+ * and server browsing, among other things, over standard IP networks.
+ * This behavior is a result of combining protocols such as multicast and
+ * DNS to add new functionality to the network (such as multicast DNS).
+ *
+ * Bonjour gives applications easy access to services over local IP
+ * networks without requiring the service or the application to support
+ * an AppleTalk or a Netbeui stack, and without requiring a DNS server
+ * for the local network.
+ */
+
+
+/* _DNS_SD_H contains the mDNSResponder version number for this header file, formatted as follows:
+ * Major part of the build number * 10000 +
+ * minor part of the build number * 100
+ * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as
+ * version 1080400. This allows C code to do simple greater-than and less-than comparisons:
+ * e.g. an application that requires the DNSServiceGetProperty() call (new in mDNSResponder-126) can check:
+ *
+ * #if _DNS_SD_H+0 >= 1260000
+ * ... some C code that calls DNSServiceGetProperty() ...
+ * #endif
+ *
+ * The version defined in this header file symbol allows for compile-time
+ * checking, so that C code building with earlier versions of the header file
+ * can avoid compile errors trying to use functions that aren't even defined
+ * in those earlier versions. Similar checks may also be performed at run-time:
+ * => weak linking -- to avoid link failures if run with an earler
+ * version of the library that's missing some desired symbol, or
+ * => DNSServiceGetProperty(DaemonVersion) -- to verify whether the running daemon
+ * ("system service" on Windows) meets some required minimum functionality level.
+ */
+
#ifndef _DNS_SD_H
-#define _DNS_SD_H
+#define _DNS_SD_H 1610100
#ifdef __cplusplus
extern "C" {
#endif
/* standard calling convention under Win32 is __stdcall */
-#if defined(_WIN32)
+/* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */
+/* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */
+#if defined(_WIN32) && !defined(EFI32) && !defined(EFI64)
#define DNSSD_API __stdcall
#else
#define DNSSD_API
#endif
-#if defined(__FreeBSD_version) && (__FreeBSD_version < 500000)
/* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */
+#if defined(__FreeBSD__) && (__FreeBSD__ < 5)
#include <sys/types.h>
+
+/* Likewise, on Sun, standard integer types are in sys/types.h */
#elif defined(__sun__)
#include <sys/types.h>
+
+/* EFI does not have stdint.h, or anything else equivalent */
+#elif defined(EFI32) || defined(EFI64)
+typedef UINT8 uint8_t;
+typedef INT8 int8_t;
+typedef UINT16 uint16_t;
+typedef INT16 int16_t;
+typedef UINT32 uint32_t;
+typedef INT32 int32_t;
+
+/* Windows has its own differences */
#elif defined(_WIN32)
#include <windows.h>
#define _UNUSED
typedef UINT32 uint32_t;
typedef INT32 int32_t;
#endif
+
+/* All other Posix platforms use stdint.h */
#else
#include <stdint.h>
#endif
typedef struct _DNSServiceRef_t *DNSServiceRef;
typedef struct _DNSRecordRef_t *DNSRecordRef;
-/* General flags used in functions defined below */
+struct sockaddr;
+
+/*! @enum General flags
+ * Most DNS-SD API functions and callbacks include a DNSServiceFlags parameter.
+ * As a general rule, any given bit in the 32-bit flags field has a specific fixed meaning,
+ * regardless of the function or callback being used. For any given function or callback,
+ * typically only a subset of the possible flags are meaningful, and all others should be zero.
+ * The discussion section for each API call describes which flags are valid for that call
+ * and callback. In some cases, for a particular call, it may be that no flags are currently
+ * defined, in which case the DNSServiceFlags parameter exists purely to allow future expansion.
+ * In all cases, developers should expect that in future releases, it is possible that new flag
+ * values will be defined, and write code with this in mind. For example, code that tests
+ * if (flags == kDNSServiceFlagsAdd) ...
+ * will fail if, in a future release, another bit in the 32-bit flags field is also set.
+ * The reliable way to test whether a particular bit is set is not with an equality test,
+ * but with a bitwise mask:
+ * if (flags & kDNSServiceFlagsAdd) ...
+ */
enum
{
kDNSServiceFlagsMoreComing = 0x1,
/* MoreComing indicates to a callback that at least one more result is
* queued and will be delivered following immediately after this one.
- * Applications should not update their UI to display browse
- * results when the MoreComing flag is set, because this would
- * result in a great deal of ugly flickering on the screen.
- * Applications should instead wait until until MoreComing is not set,
- * and then update their UI.
+ * When the MoreComing flag is set, applications should not immediately
+ * update their UI, because this can result in a great deal of ugly flickering
+ * on the screen, and can waste a great deal of CPU time repeatedly updating
+ * the screen with content that is then immediately erased, over and over.
+ * Applications should wait until until MoreComing is not set, and then
+ * update their UI when no more changes are imminent.
* When MoreComing is not set, that doesn't mean there will be no more
* answers EVER, just that there are no more answers immediately
* available right now at this instant. If more answers become available
kDNSServiceFlagsDefault = 0x4,
/* Flags for domain enumeration and browse/query reply callbacks.
* "Default" applies only to enumeration and is only valid in
- * conjuction with "Add". An enumeration callback with the "Add"
+ * conjunction with "Add". An enumeration callback with the "Add"
* flag NOT set indicates a "Remove", i.e. the domain is no longer
* valid.
*/
kDNSServiceFlagsNoAutoRename = 0x8,
/* Flag for specifying renaming behavior on name conflict when registering
* non-shared records. By default, name conflicts are automatically handled
- * by renaming the service. NoAutoRename overrides this behavior - with this
- * flag set, name conflicts will result in a callback. The NoAutorename flag
+ * by renaming the service. NoAutoRename overrides this behavior - with this
+ * flag set, name conflicts will result in a callback. The NoAutorename flag
* is only valid if a name is explicitly specified when registering a service
* (i.e. the default name is not used.)
*/
kDNSServiceFlagsShared = 0x10,
kDNSServiceFlagsUnique = 0x20,
/* Flag for registering individual records on a connected
- * DNSServiceRef. Shared indicates that there may be multiple records
- * with this name on the network (e.g. PTR records). Unique indicates that the
+ * DNSServiceRef. Shared indicates that there may be multiple records
+ * with this name on the network (e.g. PTR records). Unique indicates that the
* record's name is to be unique on the network (e.g. SRV records).
*/
* (queries from hosts more than one hop away; hosts not directly connected to the local link).
*/
- kDNSServiceFlagsForceMulticast = 0x400
- /* Flag for signifying that a query or registration should be performed exclusively via multicast DNS,
- * even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS.
+ kDNSServiceFlagsForceMulticast = 0x400,
+ /* Flag for signifying that a query or registration should be performed exclusively via multicast
+ * DNS, even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS.
+ */
+
+ kDNSServiceFlagsForce = 0x800,
+ /* Flag for signifying a "stronger" variant of an operation.
+ * Currently defined only for DNSServiceReconfirmRecord(), where it forces a record to
+ * be removed from the cache immediately, instead of querying for a few seconds before
+ * concluding that the record is no longer valid and then removing it. This flag should
+ * be used with caution because if a service browsing PTR record is indeed still valid
+ * on the network, forcing its removal will result in a user-interface flap -- the
+ * discovered service instance will disappear, and then re-appear moments later.
+ */
+
+ kDNSServiceFlagsReturnIntermediates = 0x1000,
+ /* Flag for returning intermediate results.
+ * For example, if a query results in an authoritative NXDomain (name does not exist)
+ * then that result is returned to the client. However the query is not implicitly
+ * cancelled -- it remains active and if the answer subsequently changes
+ * (e.g. because a VPN tunnel is subsequently established) then that positive
+ * result will still be returned to the client.
+ * Similarly, if a query results in a CNAME record, then in addition to following
+ * the CNAME referral, the intermediate CNAME result is also returned to the client.
+ * When this flag is not set, NXDomain errors are not returned, and CNAME records
+ * are followed silently without informing the client of the intermediate steps.
+ */
+
+ /* Previous name for kDNSServiceFlagsReturnIntermediates flag (not used externally) */
+ #define kDNSServiceFlagsReturnCNAME kDNSServiceFlagsReturnIntermediates
+
+ kDNSServiceFlagsNonBrowsable = 0x2000,
+ /* A service registered with the NonBrowsable flag set can be resolved using
+ * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse().
+ * This is for cases where the name is actually a GUID; it is found by other means;
+ * there is no end-user benefit to browsing to find a long list of opaque GUIDs.
+ * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising
+ * an associated PTR record.
+ */
+
+ kDNSServiceFlagsShareConnection = 0x4000
+ /* For efficiency, clients that perform many concurrent operations may want to use a
+ * single Unix Domain Socket connection with the background daemon, instead of having a
+ * separate connection for each independent operation. To use this mode, clients first
+ * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef.
+ * For each subsequent operation that is to share that same connection, the client copies
+ * the MainRef, and then passes the address of that copy, setting the ShareConnection flag
+ * to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef;
+ * it's a copy of an existing DNSServiceRef whose connection information should be reused.
+ *
+ * For example:
+ *
+ * DNSServiceErrorType error;
+ * DNSServiceRef MainRef;
+ * error = DNSServiceCreateConnection(&MainRef);
+ * if (error) ...
+ * DNSServiceRef BrowseRef = MainRef; // Important: COPY the primary DNSServiceRef first...
+ * error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy
+ * if (error) ...
+ * ...
+ * DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation
+ * DNSServiceRefDeallocate(MainRef); // Terminate the shared connection
+ *
+ * Notes:
+ *
+ * 1. Collective kDNSServiceFlagsMoreComing flag
+ * When callbacks are invoked using a shared DNSServiceRef, the
+ * kDNSServiceFlagsMoreComing flag applies collectively to *all* active
+ * operations sharing the same DNSServiceRef. If the MoreComing flag is
+ * set it means that there are more results queued on this DNSServiceRef,
+ * but not necessarily more results for this particular callback function.
+ * The implication of this for client programmers is that when a callback
+ * is invoked with the MoreComing flag set, the code should update its
+ * internal data structures with the new result, and set a variable indicating
+ * that its UI needs to be updated. Then, later when a callback is eventually
+ * invoked with the MoreComing flag not set, the code should update *all*
+ * stale UI elements related to that shared DNSServiceRef that need updating,
+ * not just the UI elements related to the particular callback that happened
+ * to be the last one to be invoked.
+ *
+ * 2. Only share DNSServiceRef's created with DNSServiceCreateConnection
+ * Calling DNSServiceCreateConnection(&ref) creates a special shareable DNSServiceRef.
+ * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
+ * cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
+ *
+ * 3. Don't double-deallocate
+ * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates
+ * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef
+ * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref))
+ * automatically terminates the shared connection and all operations that were still using it.
+ * After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's.
+ * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt
+ * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses
+ * to freed memory, leading to crashes or other equally undesirable results.
+ */
+
+ };
+
+/* Possible protocols for DNSServiceNATPortMappingCreate(). */
+enum
+ {
+ kDNSServiceProtocol_IPv4 = 0x01,
+ kDNSServiceProtocol_IPv6 = 0x02,
+ /* 0x04 and 0x08 reserved for future internetwork protocols */
+
+ kDNSServiceProtocol_UDP = 0x10,
+ kDNSServiceProtocol_TCP = 0x20
+ /* 0x40 and 0x80 reserved for future transport protocols, e.g. SCTP [RFC 2960]
+ * or DCCP [RFC 4340]. If future NAT gateways are created that support port
+ * mappings for these protocols, new constants will be defined here.
*/
};
kDNSServiceType_HINFO = 13, /* Host information. */
kDNSServiceType_MINFO = 14, /* Mailbox information. */
kDNSServiceType_MX = 15, /* Mail routing information. */
- kDNSServiceType_TXT = 16, /* One or more text strings. */
+ kDNSServiceType_TXT = 16, /* One or more text strings (NOT "zero or more..."). */
kDNSServiceType_RP = 17, /* Responsible person. */
kDNSServiceType_AFSDB = 18, /* AFS cell database. */
kDNSServiceType_X25 = 19, /* X_25 calling address. */
kDNSServiceType_KEY = 25, /* Security key. */
kDNSServiceType_PX = 26, /* X.400 mail mapping. */
kDNSServiceType_GPOS = 27, /* Geographical position (withdrawn). */
- kDNSServiceType_AAAA = 28, /* Ip6 Address. */
+ kDNSServiceType_AAAA = 28, /* IPv6 Address. */
kDNSServiceType_LOC = 29, /* Location Information. */
kDNSServiceType_NXT = 30, /* Next domain (security). */
kDNSServiceType_EID = 31, /* Endpoint identifier. */
kDNSServiceType_NAPTR = 35, /* Naming Authority PoinTeR */
kDNSServiceType_KX = 36, /* Key Exchange */
kDNSServiceType_CERT = 37, /* Certification record */
- kDNSServiceType_A6 = 38, /* IPv6 address (deprecates AAAA) */
+ kDNSServiceType_A6 = 38, /* IPv6 Address (deprecated) */
kDNSServiceType_DNAME = 39, /* Non-terminal DNAME (for IPv6) */
- kDNSServiceType_SINK = 40, /* Kitchen sink (experimentatl) */
+ kDNSServiceType_SINK = 40, /* Kitchen sink (experimental) */
kDNSServiceType_OPT = 41, /* EDNS0 option (meta-RR) */
+ kDNSServiceType_APL = 42, /* Address Prefix List */
+ kDNSServiceType_DS = 43, /* Delegation Signer */
+ kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */
+ kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */
+ kDNSServiceType_RRSIG = 46, /* RRSIG */
+ kDNSServiceType_NSEC = 47, /* NSEC */
+ kDNSServiceType_DNSKEY = 48, /* DNSKEY */
+ kDNSServiceType_DHCID = 49, /* DHCID */
+
kDNSServiceType_TKEY = 249, /* Transaction key */
kDNSServiceType_TSIG = 250, /* Transaction signature. */
kDNSServiceType_IXFR = 251, /* Incremental zone transfer. */
kDNSServiceType_ANY = 255 /* Wildcard match. */
};
-
/* possible error code values */
enum
{
- kDNSServiceErr_NoError = 0,
- kDNSServiceErr_Unknown = -65537, /* 0xFFFE FFFF */
- kDNSServiceErr_NoSuchName = -65538,
- kDNSServiceErr_NoMemory = -65539,
- kDNSServiceErr_BadParam = -65540,
- kDNSServiceErr_BadReference = -65541,
- kDNSServiceErr_BadState = -65542,
- kDNSServiceErr_BadFlags = -65543,
- kDNSServiceErr_Unsupported = -65544,
- kDNSServiceErr_NotInitialized = -65545,
- kDNSServiceErr_AlreadyRegistered = -65547,
- kDNSServiceErr_NameConflict = -65548,
- kDNSServiceErr_Invalid = -65549,
- kDNSServiceErr_Firewall = -65550,
- kDNSServiceErr_Incompatible = -65551, /* client library incompatible with daemon */
- kDNSServiceErr_BadInterfaceIndex = -65552,
- kDNSServiceErr_Refused = -65553,
- kDNSServiceErr_NoSuchRecord = -65554,
- kDNSServiceErr_NoAuth = -65555,
- kDNSServiceErr_NoSuchKey = -65556,
- kDNSServiceErr_NATTraversal = -65557,
- kDNSServiceErr_DoubleNAT = -65558,
- kDNSServiceErr_BadTime = -65559
+ kDNSServiceErr_NoError = 0,
+ kDNSServiceErr_Unknown = -65537, /* 0xFFFE FFFF */
+ kDNSServiceErr_NoSuchName = -65538,
+ kDNSServiceErr_NoMemory = -65539,
+ kDNSServiceErr_BadParam = -65540,
+ kDNSServiceErr_BadReference = -65541,
+ kDNSServiceErr_BadState = -65542,
+ kDNSServiceErr_BadFlags = -65543,
+ kDNSServiceErr_Unsupported = -65544,
+ kDNSServiceErr_NotInitialized = -65545,
+ kDNSServiceErr_AlreadyRegistered = -65547,
+ kDNSServiceErr_NameConflict = -65548,
+ kDNSServiceErr_Invalid = -65549,
+ kDNSServiceErr_Firewall = -65550,
+ kDNSServiceErr_Incompatible = -65551, /* client library incompatible with daemon */
+ kDNSServiceErr_BadInterfaceIndex = -65552,
+ kDNSServiceErr_Refused = -65553,
+ kDNSServiceErr_NoSuchRecord = -65554,
+ kDNSServiceErr_NoAuth = -65555,
+ kDNSServiceErr_NoSuchKey = -65556,
+ kDNSServiceErr_NATTraversal = -65557,
+ kDNSServiceErr_DoubleNAT = -65558,
+ kDNSServiceErr_BadTime = -65559, /* Codes up to here existed in Tiger */
+ kDNSServiceErr_BadSig = -65560,
+ kDNSServiceErr_BadKey = -65561,
+ kDNSServiceErr_Transient = -65562,
+ kDNSServiceErr_ServiceNotRunning = -65563, /* Background daemon not running */
+ kDNSServiceErr_NATPortMappingUnsupported = -65564, /* No NAT or if the NAT doesn't support NAT-PMP or UPnP. */
+ kDNSServiceErr_NATPortMappingDisabled = -65565 /* NAT supports NAT-PMP or UPnP but it's disabled by the administrator */
+
/* mDNS Error codes are in the range
* FFFE FF00 (-65792) to FFFE FFFF (-65537) */
};
-
/* Maximum length, in bytes, of a service name represented as a */
/* literal C-String, including the terminating NULL at the end. */
*/
-/*
+/*
* Constants for specifying an interface index
*
* Specific interface indexes are identified via a 32-bit unsigned integer returned
* by the if_nametoindex() family of calls.
- *
+ *
* If the client passes 0 for interface index, that means "do the right thing",
* which (at present) means, "if the name is in an mDNS local multicast domain
- * (e.g. 'local.', '254.169.in-addr.arpa.', '0.8.E.F.ip6.arpa.') then multicast
+ * (e.g. 'local.', '254.169.in-addr.arpa.', '{8,9,A,B}.E.F.ip6.arpa.') then multicast
* on all applicable interfaces, otherwise send via unicast to the appropriate
* DNS server." Normally, most clients will use 0 for interface index to
* automatically get the default sensible behaviour.
- *
+ *
* If the client passes a positive interface index, then for multicast names that
* indicates to do the operation only on that one interface. For unicast names the
* interface index is ignored unless kDNSServiceFlagsForceMulticast is also set.
- *
+ *
* If the client passes kDNSServiceInterfaceIndexLocalOnly when registering
* a service, then that service will be found *only* by other local clients
* on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly
* running on the same machine, this allows the client to advertise that service
* in a way such that it does not inadvertently appear in service lists on
* all the other machines on the network.
- *
+ *
* If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing
* then it will find *all* records registered on that same local machine.
* Clients explicitly wishing to discover *only* LocalOnly services can
*/
#define kDNSServiceInterfaceIndexAny 0
-#define kDNSServiceInterfaceIndexLocalOnly ( (uint32_t) -1 )
-
+#define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1)
+#define kDNSServiceInterfaceIndexUnicast ((uint32_t)-2)
typedef uint32_t DNSServiceFlags;
-typedef int32_t DNSServiceErrorType;
+typedef uint32_t DNSServiceProtocol;
+typedef int32_t DNSServiceErrorType;
/*********************************************************************************************
*
- * Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions
+ * Version checking
*
*********************************************************************************************/
+/* DNSServiceGetProperty() Parameters:
+ *
+ * property: The requested property.
+ * Currently the only property defined is kDNSServiceProperty_DaemonVersion.
+ *
+ * result: Place to store result.
+ * For retrieving DaemonVersion, this should be the address of a uint32_t.
+ *
+ * size: Pointer to uint32_t containing size of the result location.
+ * For retrieving DaemonVersion, this should be sizeof(uint32_t).
+ * On return the uint32_t is updated to the size of the data returned.
+ * For DaemonVersion, the returned size is always sizeof(uint32_t), but
+ * future properties could be defined which return variable-sized results.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning
+ * if the daemon (or "system service" on Windows) is not running.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceGetProperty
+ (
+ const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */
+ void *result, /* Pointer to place to store result */
+ uint32_t *size /* size of result location */
+ );
+
+/*
+ * When requesting kDNSServiceProperty_DaemonVersion, the result pointer must point
+ * to a 32-bit unsigned integer, and the size parameter must be set to sizeof(uint32_t).
+ *
+ * On return, the 32-bit unsigned integer contains the version number, formatted as follows:
+ * Major part of the build number * 10000 +
+ * minor part of the build number * 100
+ *
+ * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as
+ * version 1080400. This allows applications to do simple greater-than and less-than comparisons:
+ * e.g. an application that requires at least mDNSResponder-108.4 can check:
+ *
+ * if (version >= 1080400) ...
+ *
+ * Example usage:
+ *
+ * uint32_t version;
+ * uint32_t size = sizeof(version);
+ * DNSServiceErrorType err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &version, &size);
+ * if (!err) printf("Bonjour version is %d.%d\n", version / 10000, version / 100 % 100);
+ */
+
+#define kDNSServiceProperty_DaemonVersion "DaemonVersion"
+
+
+/*********************************************************************************************
+ *
+ * Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions
+ *
+ *********************************************************************************************/
/* DNSServiceRefSockFD()
*
* Access underlying Unix domain socket for an initialized DNSServiceRef.
- * The DNS Service Discovery implmementation uses this socket to communicate between
- * the client and the mDNSResponder daemon. The application MUST NOT directly read from
- * or write to this socket. Access to the socket is provided so that it can be used as a
- * run loop source, or in a select() loop: when data is available for reading on the socket,
- * DNSServiceProcessResult() should be called, which will extract the daemon's reply from
- * the socket, and pass it to the appropriate application callback. By using a run loop or
- * select(), results from the daemon can be processed asynchronously. Without using these
- * constructs, DNSServiceProcessResult() will block until the response from the daemon arrives.
- * The client is responsible for ensuring that the data on the socket is processed in a timely
- * fashion - the daemon may terminate its connection with a client that does not clear its
- * socket buffer.
- *
- * sdRef: A DNSServiceRef initialized by any of the DNSService calls.
+ * The DNS Service Discovery implementation uses this socket to communicate between the client and
+ * the mDNSResponder daemon. The application MUST NOT directly read from or write to this socket.
+ * Access to the socket is provided so that it can be used as a kqueue event source, a CFRunLoop
+ * event source, in a select() loop, etc. When the underlying event management subsystem (kqueue/
+ * select/CFRunLoop etc.) indicates to the client that data is available for reading on the
+ * socket, the client should call DNSServiceProcessResult(), which will extract the daemon's
+ * reply from the socket, and pass it to the appropriate application callback. By using a run
+ * loop or select(), results from the daemon can be processed asynchronously. Alternatively,
+ * a client can choose to fork a thread and have it loop calling "DNSServiceProcessResult(ref);"
+ * If DNSServiceProcessResult() is called when no data is available for reading on the socket, it
+ * will block until data does become available, and then process the data and return to the caller.
+ * When data arrives on the socket, the client is responsible for calling DNSServiceProcessResult(ref)
+ * in a timely fashion -- if the client allows a large backlog of data to build up the daemon
+ * may terminate the connection.
+ *
+ * sdRef: A DNSServiceRef initialized by any of the DNSService calls.
*
* return value: The DNSServiceRef's underlying socket descriptor, or -1 on
* error.
/* DNSServiceProcessResult()
*
- * Read a reply from the daemon, calling the appropriate application callback. This call will
- * block until the daemon's response is received. Use DNSServiceRefSockFD() in
+ * Read a reply from the daemon, calling the appropriate application callback. This call will
+ * block until the daemon's response is received. Use DNSServiceRefSockFD() in
* conjunction with a run loop or select() to determine the presence of a response from the
- * server before calling this function to process the reply without blocking. Call this function
- * at any point if it is acceptable to block until the daemon's response arrives. Note that the
+ * server before calling this function to process the reply without blocking. Call this function
+ * at any point if it is acceptable to block until the daemon's response arrives. Note that the
* client is responsible for ensuring that DNSServiceProcessResult() is called whenever there is
* a reply from the daemon - the daemon may terminate its connection with a client that does not
* process the daemon's responses.
*
* Note: If the reference was initialized with DNSServiceCreateConnection(), any DNSRecordRefs
* created via this reference will be invalidated by this call - the resource records are
- * deregistered, and their DNSRecordRefs may not be used in subsequent functions. Similarly,
+ * deregistered, and their DNSRecordRefs may not be used in subsequent functions. Similarly,
* if the reference was initialized with DNSServiceRegister, and an extra resource record was
* added to the service via DNSServiceAddRecord(), the DNSRecordRef created by the Add() call
* is invalidated when this function is called - the DNSRecordRef may not be used in subsequent
* functions.
*
- * Note: This call is to be used only with the DNSServiceRef defined by this API. It is
+ * Note: This call is to be used only with the DNSServiceRef defined by this API. It is
* not compatible with dns_service_discovery_ref objects defined in the legacy Mach-based
* DNSServiceDiscovery.h API.
*
* kDNSServiceFlagsAdd
* kDNSServiceFlagsDefault
*
- * interfaceIndex: Specifies the interface on which the domain exists. (The index for a given
+ * interfaceIndex: Specifies the interface on which the domain exists. (The index for a given
* interface is determined via the if_nametoindex() family of calls.)
*
* errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise indicates
/* DNSServiceEnumerateDomains() Parameters:
*
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
* then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
* and the enumeration operation will run indefinitely until the client
* terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
*
* interfaceIndex: If non-zero, specifies the interface on which to look for domains.
* (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to enumerate domains on
+ * family of calls.) Most applications will pass 0 to enumerate domains on
* all interfaces. See "Constants for specifying an interface index" for more details.
*
* callBack: The function to be called when a domain is found or the call asynchronously
* context: An application context pointer which is passed to the callback function
* (may be NULL).
*
- * return value: Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
* errors are delivered to the callback), otherwise returns an error code indicating
* the error that occurred (the callback is not invoked and the DNSServiceRef
- * is not initialized.)
+ * is not initialized).
*/
DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
*
* sdRef: The DNSServiceRef initialized by DNSServiceRegister().
*
- * flags: Currently unused, reserved for future use.
+ * flags: When a name is successfully registered, the callback will be
+ * invoked with the kDNSServiceFlagsAdd flag set. When Wide-Area
+ * DNS-SD is in use, it is possible for a single service to get
+ * more than one success callback (e.g. one in the "local" multicast
+ * DNS domain, and another in a wide-area unicast DNS domain).
+ * If a successfully-registered name later suffers a name conflict
+ * or similar problem and has to be deregistered, the callback will
+ * be invoked with the kDNSServiceFlagsAdd flag not set. The callback
+ * is *not* invoked in the case where the caller explicitly terminates
+ * the service registration by calling DNSServiceRefDeallocate(ref);
*
* errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
* indicate the failure that occurred (including name conflicts,
);
-/* DNSServiceRegister() Parameters:
+/* DNSServiceRegister() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
* then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
* and the registration will remain active indefinitely until the client
* terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
*
* interfaceIndex: If non-zero, specifies the interface on which to register the service
* (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to register on all
+ * family of calls.) Most applications will pass 0 to register on all
* available interfaces. See "Constants for specifying an interface index" for more details.
*
* flags: Indicates the renaming behavior on name conflict (most applications
- * will pass 0). See flag definitions above for details.
+ * will pass 0). See flag definitions above for details.
*
* name: If non-NULL, specifies the service name to be registered.
* Most applications will not specify a name, in which case the computer
* The transport protocol must be "_tcp" or "_udp". New service types
* should be registered at <http://www.dns-sd.org/ServiceTypes.html>.
*
+ * Additional subtypes of the primary service type (where a service
+ * type has defined subtypes) follow the primary service type in a
+ * comma-separated list, with no additional spaces, e.g.
+ * "_primarytype._tcp,_subtype1,_subtype2,_subtype3"
+ * Subtypes provide a mechanism for filtered browsing: A client browsing
+ * for "_primarytype._tcp" will discover all instances of this type;
+ * a client browsing for "_primarytype._tcp,_subtype2" will discover only
+ * those instances that were registered with "_subtype2" in their list of
+ * registered subtypes.
+ *
+ * The subtype mechanism can be illustrated with some examples using the
+ * dns-sd command-line tool:
+ *
+ * % dns-sd -R Simple _test._tcp "" 1001 &
+ * % dns-sd -R Better _test._tcp,HasFeatureA "" 1002 &
+ * % dns-sd -R Best _test._tcp,HasFeatureA,HasFeatureB "" 1003 &
+ *
+ * Now:
+ * % dns-sd -B _test._tcp # will find all three services
+ * % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best"
+ * % dns-sd -B _test._tcp,HasFeatureB # finds only "Best"
+ *
* domain: If non-NULL, specifies the domain on which to advertise the service.
* Most applications will not specify a domain, instead automatically
* registering in the default domain(s).
*
- * host: If non-NULL, specifies the SRV target host name. Most applications
+ * host: If non-NULL, specifies the SRV target host name. Most applications
* will not specify a host, instead automatically using the machine's
- * default host name(s). Note that specifying a non-NULL host does NOT
+ * default host name(s). Note that specifying a non-NULL host does NOT
* create an address record for that host - the application is responsible
* for ensuring that the appropriate address record exists, or creating it
* via DNSServiceRegisterRecord().
* port: The port, in network byte order, on which the service accepts connections.
* Pass 0 for a "placeholder" service (i.e. a service that will not be discovered
* by browsing, but will cause a name conflict if another client tries to
- * register that same name). Most clients will not use placeholder services.
+ * register that same name). Most clients will not use placeholder services.
*
- * txtLen: The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL.
+ * txtLen: The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL.
*
* txtRecord: The TXT record rdata. A non-NULL txtRecord MUST be a properly formatted DNS
* TXT record, i.e. <length byte> <data> <length byte> <data> ...
* i.e. it creates a TXT record of length one containing a single empty string.
* RFC 1035 doesn't allow a TXT record to contain *zero* strings, so a single empty
* string is the smallest legal DNS TXT record.
+ * As with the other parameters, the DNSServiceRegister call copies the txtRecord
+ * data; e.g. if you allocated the storage for the txtRecord parameter with malloc()
+ * then you can safely free that memory right after the DNSServiceRegister call returns.
*
* callBack: The function to be called when the registration completes or asynchronously
- * fails. The client MAY pass NULL for the callback - The client will NOT be notified
+ * fails. The client MAY pass NULL for the callback - The client will NOT be notified
* of the default values picked on its behalf, and the client will NOT be notified of any
* asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration
- * of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL.
+ * of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL.
* The client may still deregister the service at any time via DNSServiceRefDeallocate().
*
* context: An application context pointer which is passed to the callback function
* (may be NULL).
*
- * return value: Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
* errors are delivered to the callback), otherwise returns an error code indicating
* the error that occurred (the callback is never invoked and the DNSServiceRef
- * is not initialized.)
- *
+ * is not initialized).
*/
DNSServiceErrorType DNSSD_API DNSServiceRegister
/* DNSServiceAddRecord()
*
- * Add a record to a registered service. The name of the record will be the same as the
+ * Add a record to a registered service. The name of the record will be the same as the
* registered service's name.
* The record can later be updated or deregistered by passing the RecordRef initialized
* by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
*
+ * Note that the DNSServiceAddRecord/UpdateRecord/RemoveRecord are *NOT* thread-safe
+ * with respect to a single DNSServiceRef. If you plan to have multiple threads
+ * in your program simultaneously add, update, or remove records from the same
+ * DNSServiceRef, then it's the caller's responsibility to use a mutext lock
+ * or take similar appropriate precautions to serialize those calls.
+ *
*
* Parameters;
*
* sdRef: A DNSServiceRef initialized by DNSServiceRegister().
*
- * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
+ * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
* call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
* If the above DNSServiceRef is passed to DNSServiceRefDeallocate(), RecordRef is also
* invalidated and may not be used further.
*
* rdata: The raw rdata to be contained in the added resource record.
*
- * ttl: The time to live of the resource record, in seconds. Pass 0 to use a default value.
+ * ttl: The time to live of the resource record, in seconds. Pass 0 to use a default value.
*
* return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
* error code indicating the error that occurred (the RecordRef is not initialized).
/* DNSServiceUpdateRecord
*
- * Update a registered resource record. The record must either be:
+ * Update a registered resource record. The record must either be:
* - The primary txt record of a service registered via DNSServiceRegister()
* - A record added to a registered service via DNSServiceAddRecord()
* - An individual record registered by DNSServiceRegisterRecord()
* flags: Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd.
* See flag definitions for details.
*
- * interfaceIndex: The interface on which the service is advertised. This index should
+ * interfaceIndex: The interface on which the service is advertised. This index should
* be passed to DNSServiceResolve() when resolving the service.
*
* errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
+ * indicate the failure that occurred. Other parameters are undefined if
* the errorCode is nonzero.
*
* serviceName: The discovered service name. This name should be displayed to the user,
/* DNSServiceBrowse() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
* then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
* and the browse operation will run indefinitely until the client
* terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
*
* interfaceIndex: If non-zero, specifies the interface on which to browse for services
* (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to browse on all available
+ * family of calls.) Most applications will pass 0 to browse on all available
* interfaces. See "Constants for specifying an interface index" for more details.
*
* regtype: The service type being browsed for followed by the protocol, separated by a
- * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
+ * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
+ * A client may optionally specify a single subtype to perform filtered browsing:
+ * e.g. browsing for "_primarytype._tcp,_subtype" will discover only those
+ * instances of "_primarytype._tcp" that were registered specifying "_subtype"
+ * in their list of registered subtypes.
*
* domain: If non-NULL, specifies the domain on which to browse for services.
* Most applications will not specify a domain, instead browsing on the
* context: An application context pointer which is passed to the callback function
* (may be NULL).
*
- * return value: Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
* errors are delivered to the callback), otherwise returns an error code indicating
* the error that occurred (the callback is not invoked and the DNSServiceRef
- * is not initialized.)
+ * is not initialized).
*/
DNSServiceErrorType DNSSD_API DNSServiceBrowse
*
* sdRef: The DNSServiceRef initialized by DNSServiceResolve().
*
- * flags: Currently unused, reserved for future use.
+ * flags: Possible values: kDNSServiceFlagsMoreComing
*
* interfaceIndex: The interface on which the service was resolved.
*
* errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
+ * indicate the failure that occurred. Other parameters are undefined if
* the errorCode is nonzero.
*
* fullname: The full service domain name, in the form <servicename>.<protocol>.<domain>.
* special-purpose functions included in this API that take fullname parameters.
* See "Notes on DNS Name Escaping" earlier in this file for more details.)
*
- * hosttarget: The target hostname of the machine providing the service. This name can
+ * hosttarget: The target hostname of the machine providing the service. This name can
* be passed to functions like gethostbyname() to identify the host's IP address.
*
* port: The port, in network byte order, on which connections are accepted for this service.
*
* txtRecord: The service's primary txt record, in standard txt record format.
*
-
* context: The context pointer that was passed to the callout.
*
+ * NOTE: In earlier versions of this header file, the txtRecord parameter was declared "const char *"
+ * This is incorrect, since it contains length bytes which are values in the range 0 to 255, not -128 to +127.
+ * Depending on your compiler settings, this change may cause signed/unsigned mismatch warnings.
+ * These should be fixed by updating your own callback function definition to match the corrected
+ * function signature using "const unsigned char *txtRecord". Making this change may also fix inadvertent
+ * bugs in your callback function, where it could have incorrectly interpreted a length byte with value 250
+ * as being -6 instead, with various bad consequences ranging from incorrect operation to software crashes.
+ * If you need to maintain portable code that will compile cleanly with both the old and new versions of
+ * this header file, you should update your callback function definition to use the correct unsigned value,
+ * and then in the place where you pass your callback function to DNSServiceResolve(), use a cast to eliminate
+ * the compiler warning, e.g.:
+ * DNSServiceResolve(sd, flags, index, name, regtype, domain, (DNSServiceResolveReply)MyCallback, context);
+ * This will ensure that your code compiles cleanly without warnings (and more importantly, works correctly)
+ * with both the old header and with the new corrected version.
+ *
*/
typedef void (DNSSD_API *DNSServiceResolveReply)
const char *hosttarget,
uint16_t port,
uint16_t txtLen,
- const char *txtRecord,
+ const unsigned char *txtRecord,
void *context
);
/* DNSServiceResolve() Parameters
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
* then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
* and the resolve operation will run indefinitely until the client
* terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
*
- * flags: Currently ignored, reserved for future use.
+ * flags: Specifying kDNSServiceFlagsForceMulticast will cause query to be
+ * performed with a link-local mDNS query, even if the name is an
+ * apparently non-local name (i.e. a name not ending in ".local.")
*
* interfaceIndex: The interface on which to resolve the service. If this resolve call is
* as a result of a currently active DNSServiceBrowse() operation, then the
* context: An application context pointer which is passed to the callback function
* (may be NULL).
*
- * return value: Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
* errors are delivered to the callback), otherwise returns an error code indicating
* the error that occurred (the callback is never invoked and the DNSServiceRef
- * is not initialized.)
+ * is not initialized).
*/
DNSServiceErrorType DNSSD_API DNSServiceResolve
/*********************************************************************************************
*
- * Special Purpose Calls (most applications will not use these)
+ * Querying Individual Specific Records
+ *
+ *********************************************************************************************/
+
+/* DNSServiceQueryRecord
+ *
+ * Query for an arbitrary DNS record.
+ *
+ *
+ * DNSServiceQueryRecordReply() Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord().
+ *
+ * flags: Possible values are kDNSServiceFlagsMoreComing and
+ * kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records
+ * with a ttl of 0, i.e. "Remove" events.
+ *
+ * interfaceIndex: The interface on which the query was resolved (the index for a given
+ * interface is determined via the if_nametoindex() family of calls).
+ * See "Constants for specifying an interface index" for more details.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred. Other parameters are undefined if
+ * errorCode is nonzero.
+ *
+ * fullname: The resource record's full domain name.
+ *
+ * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * rdlen: The length, in bytes, of the resource record rdata.
+ *
+ * rdata: The raw rdata of the resource record.
+ *
+ * ttl: If the client wishes to cache the result for performance reasons,
+ * the TTL indicates how long the client may legitimately hold onto
+ * this result, in seconds. After the TTL expires, the client should
+ * consider the result no longer valid, and if it requires this data
+ * again, it should be re-fetched with a new query. Of course, this
+ * only applies to clients that cancel the asynchronous operation when
+ * they get a result. Clients that leave the asynchronous operation
+ * running can safely assume that the data remains valid until they
+ * get another callback telling them otherwise.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceQueryRecordReply)
+ (
+ DNSServiceRef DNSServiceRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ void *context
+ );
+
+
+/* DNSServiceQueryRecord() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the query operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
+ * query in a non-local domain. Without setting this flag, unicast queries
+ * will be one-shot - that is, only answers available at the time of the call
+ * will be returned. By setting this flag, answers (including Add and Remove
+ * events) that become available after the initial call is made will generate
+ * callbacks. This flag has no effect on link-local multicast queries.
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to issue the query
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Passing 0 causes the name to be queried for on all
+ * interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * fullname: The full domain name of the resource record to be queried for.
+ *
+ * rrtype: The numerical type of the resource record to be queried for
+ * (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * callBack: The function to be called when a result is found, or if the call
+ * asynchronously fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ DNSServiceQueryRecordReply callBack,
+ void *context /* may be NULL */
+ );
+
+
+/*********************************************************************************************
+ *
+ * Unified lookup of both IPv4 and IPv6 addresses for a fully qualified hostname
+ *
+ *********************************************************************************************/
+
+/* DNSServiceGetAddrInfo
+ *
+ * Queries for the IP address of a hostname by using either Multicast or Unicast DNS.
+ *
+ *
+ * DNSServiceGetAddrInfoReply() parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceGetAddrInfo().
+ *
+ * flags: Possible values are kDNSServiceFlagsMoreComing and
+ * kDNSServiceFlagsAdd.
+ *
+ * interfaceIndex: The interface to which the answers pertain.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred. Other parameters are
+ * undefined if errorCode is nonzero.
+ *
+ * hostname: The fully qualified domain name of the host to be queried for.
+ *
+ * address: IPv4 or IPv6 address.
+ *
+ * ttl: If the client wishes to cache the result for performance reasons,
+ * the TTL indicates how long the client may legitimately hold onto
+ * this result, in seconds. After the TTL expires, the client should
+ * consider the result no longer valid, and if it requires this data
+ * again, it should be re-fetched with a new query. Of course, this
+ * only applies to clients that cancel the asynchronous operation when
+ * they get a result. Clients that leave the asynchronous operation
+ * running can safely assume that the data remains valid until they
+ * get another callback telling them otherwise.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
+ (
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *hostname,
+ const struct sockaddr *address,
+ uint32_t ttl,
+ void *context
+ );
+
+
+/* DNSServiceGetAddrInfo() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
+ * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query
+ * begins and will last indefinitely until the client terminates the query
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
+ * query in a non-local domain. Without setting this flag, unicast queries
+ * will be one-shot - that is, only answers available at the time of the call
+ * will be returned. By setting this flag, answers (including Add and Remove
+ * events) that become available after the initial call is made will generate
+ * callbacks. This flag has no effect on link-local multicast queries.
+ *
+ * interfaceIndex: The interface on which to issue the query. Passing 0 causes the query to be
+ * sent on all active interfaces via Multicast or the primary interface via Unicast.
+ *
+ * protocol: Pass in kDNSServiceProtocol_IPv4 to look up IPv4 addresses, or kDNSServiceProtocol_IPv6
+ * to look up IPv6 addresses, or both to look up both kinds. If neither flag is
+ * set, the system will apply an intelligent heuristic, which is (currently)
+ * that it will attempt to look up both, except:
+ *
+ * * If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
+ * but this host has no routable IPv6 address, then the call will not try to
+ * look up IPv6 addresses for "hostname", since any addresses it found would be
+ * unlikely to be of any use anyway. Similarly, if this host has no routable
+ * IPv4 address, the call will not try to look up IPv4 addresses for "hostname".
+ *
+ * * If "hostname" is a link-local multicast DNS hostname (i.e. a ".local." name)
+ * but this host has no IPv6 address of any kind, then it will not try to look
+ * up IPv6 addresses for "hostname". Similarly, if this host has no IPv4 address
+ * of any kind, the call will not try to look up IPv4 addresses for "hostname".
+ *
+ * hostname: The fully qualified domain name of the host to be queried for.
+ *
+ * callBack: The function to be called when the query succeeds or fails asynchronously.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceProtocol protocol,
+ const char *hostname,
+ DNSServiceGetAddrInfoReply callBack,
+ void *context /* may be NULL */
+ );
+
+
+/*********************************************************************************************
+ *
+ * Special Purpose Calls:
+ * DNSServiceCreateConnection(), DNSServiceRegisterRecord(), DNSServiceReconfirmRecord()
+ * (most applications will not use these)
*
*********************************************************************************************/
*
* Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
+ * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
* the reference (via DNSServiceRefDeallocate()) severs the
* connection and deregisters all records registered on this connection.
*
* DNSServiceRegisterRecordReply() parameters:
*
* sdRef: The connected DNSServiceRef initialized by
- * DNSServiceDiscoveryConnect().
+ * DNSServiceCreateConnection().
*
- * RecordRef: The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above
+ * RecordRef: The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above
* DNSServiceRef is passed to DNSServiceRefDeallocate(), this DNSRecordRef is
* invalidated, and may not be used further.
*
*
* sdRef: A DNSServiceRef initialized by DNSServiceCreateConnection().
*
- * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
+ * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
* call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
* (To deregister ALL records registered on a single connected DNSServiceRef
* and deallocate each of their corresponding DNSServiceRecordRefs, call
*
* interfaceIndex: If non-zero, specifies the interface on which to register the record
* (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Passing 0 causes the record to be registered on all interfaces.
+ * family of calls.) Passing 0 causes the record to be registered on all interfaces.
* See "Constants for specifying an interface index" for more details.
*
* fullname: The full domain name of the resource record.
*
* rdata: A pointer to the raw rdata, as it is to appear in the DNS record.
*
- * ttl: The time to live of the resource record, in seconds. Pass 0 to use a default value.
+ * ttl: The time to live of the resource record, in seconds. Pass 0 to use a default value.
*
* callBack: The function to be called when a result is found, or if the call
* asynchronously fails (e.g. because of a name conflict.)
* context: An application context pointer which is passed to the callback function
* (may be NULL).
*
- * return value: Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
* errors are delivered to the callback), otherwise returns an error code indicating
* the error that occurred (the callback is never invoked and the DNSRecordRef is
- * not initialized.)
+ * not initialized).
*/
DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
);
-/* DNSServiceQueryRecord
- *
- * Query for an arbitrary DNS record.
- *
- *
- * DNSServiceQueryRecordReply() Callback Parameters:
+/* DNSServiceReconfirmRecord
*
- * sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord().
+ * Instruct the daemon to verify the validity of a resource record that appears
+ * to be out of date (e.g. because TCP connection to a service's target failed.)
+ * Causes the record to be flushed from the daemon's cache (as well as all other
+ * daemons' caches on the network) if the record is determined to be invalid.
+ * Use this routine conservatively. Reconfirming a record necessarily consumes
+ * network bandwidth, so this should not be done indiscriminately.
*
- * flags: Possible values are kDNSServiceFlagsMoreComing and
- * kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records
- * with a ttl of 0, i.e. "Remove" events.
+ * Parameters:
*
- * interfaceIndex: The interface on which the query was resolved (the index for a given
- * interface is determined via the if_nametoindex() family of calls).
- * See "Constants for specifying an interface index" for more details.
+ * flags: Pass kDNSServiceFlagsForce to force immediate deletion of record,
+ * instead of after some number of reconfirmation queries have gone unanswered.
*
- * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
- * errorCode is nonzero.
+ * interfaceIndex: Specifies the interface of the record in question.
+ * The caller must specify the interface.
+ * This API (by design) causes increased network traffic, so it requires
+ * the caller to be precise about which record should be reconfirmed.
+ * It is not possible to pass zero for the interface index to perform
+ * a "wildcard" reconfirmation, where *all* matching records are reconfirmed.
*
* fullname: The resource record's full domain name.
*
*
* rdata: The raw rdata of the resource record.
*
- * ttl: The resource record's time to live, in seconds.
- *
- * context: The context pointer that was passed to the callout.
- *
*/
-typedef void (DNSSD_API *DNSServiceQueryRecordReply)
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
(
- DNSServiceRef DNSServiceRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl,
- void *context
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata
);
-/* DNSServiceQueryRecord() Parameters:
+/*********************************************************************************************
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the query operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * NAT Port Mapping
*
- * flags: Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
- * query in a non-local domain. Without setting this flag, unicast queries
- * will be one-shot - that is, only answers available at the time of the call
- * will be returned. By setting this flag, answers (including Add and Remove
- * events) that become available after the initial call is made will generate
- * callbacks. This flag has no effect on link-local multicast queries.
+ *********************************************************************************************/
+
+/* DNSServiceNATPortMappingCreate
*
- * interfaceIndex: If non-zero, specifies the interface on which to issue the query
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Passing 0 causes the name to be queried for on all
- * interfaces. See "Constants for specifying an interface index" for more details.
+ * Request a port mapping in the NAT gateway which maps a port on the local machine
+ * to a public port on the NAT.
+ * The port mapping will be renewed indefinitely until the client process exits, or
+ * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate().
+ * The client callback will be invoked, informing the client of the NAT gateway's
+ * public IP address and the public port that has been allocated for this client.
+ * The client should then record this public IP address and port using whatever
+ * directory service mechanism it is using to enable peers to connect to it.
+ * (Clients advertising services using Wide-Area DNS-SD DO NOT need to use this API
+ * -- when a client calls DNSServiceRegister() NAT mappings are automatically created
+ * and the public IP address and port for the service are recorded in the global DNS.
+ * Only clients using some directory mechanism other than Wide-Area DNS-SD need to use
+ * this API to explicitly map their own ports.)
+ * It's possible that the client callback could be called multiple times, for example
+ * if the NAT gateway's IP address changes, or if a configuration change results in a
+ * different public port being mapped for this client. Over the lifetime of any long-lived
+ * port mapping, the client should be prepared to handle these notifications of changes
+ * in the environment, and should update its recorded address and/or port as appropriate.
*
- * fullname: The full domain name of the resource record to be queried for.
*
- * rrtype: The numerical type of the resource record to be queried for
- * (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ * DNSServiceNATPortMappingReply() parameters:
*
- * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ * sdRef: The DNSServiceRef initialized by DNSServiceNATPortMappingCreate().
*
- * callBack: The function to be called when a result is found, or if the call
- * asynchronously fails.
+ * flags: Currently unused, reserved for future use.
*
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
+ * interfaceIndex: The interface through which the NAT gateway is reached.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred. Other parameters are
+ * undefined if errorCode is nonzero.
+ *
+ * publicAddress: Four byte IPv4 address in network byte order.
+ *
+ * protocol: Will be kDNSServiceProtocol_UDP or kDNSServiceProtocol_TCP or both.
+ *
+ * privatePort: The port on the local machine that was mapped.
+ *
+ * publicPort: The actual public port in the NAT gateway that was mapped.
+ * This is very likely to be different than the requested public port.
+ *
+ * ttl: The lifetime of the NAT port mapping created on the gateway.
+ * This controls how quickly stale mappings will be garbage-collected
+ * if the client machine crashes, suffers a power failure, is disconnected
+ * from the network, or suffers some other unfortunate demise which
+ * causes it to vanish without explicitly removing its NAT port mapping.
+ * It's possible that the ttl value will differ from the requested ttl value.
+ *
+ * context: The context pointer that was passed to the callout.
*
- * return value: Returns kDNSServiceErr_NoError on succeses (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred (the callback is never invoked and the DNSServiceRef
- * is not initialized.)
*/
-DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
+typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- DNSServiceQueryRecordReply callBack,
- void *context /* may be NULL */
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ uint32_t publicAddress, /* four byte IPv4 address in network byte order */
+ DNSServiceProtocol protocol,
+ uint16_t privatePort,
+ uint16_t publicPort, /* may be different than the requested port */
+ uint32_t ttl, /* may be different than the requested ttl */
+ void *context
);
-/* DNSServiceReconfirmRecord
+/* DNSServiceNATPortMappingCreate() Parameters:
*
- * Instruct the daemon to verify the validity of a resource record that appears to
- * be out of date (e.g. because tcp connection to a service's target failed.)
- * Causes the record to be flushed from the daemon's cache (as well as all other
- * daemons' caches on the network) if the record is determined to be invalid.
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
+ * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat
+ * port mapping will last indefinitely until the client terminates the port
+ * mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate().
*
- * Parameters:
+ * flags: Currently ignored, reserved for future use.
*
- * flags: Currently unused, reserved for future use.
+ * interfaceIndex: The interface on which to create port mappings in a NAT gateway. Passing 0 causes
+ * the port mapping request to be sent on the primary interface.
*
- * interfaceIndex: If non-zero, specifies the interface of the record in question.
- * Passing 0 causes all instances of this record to be reconfirmed.
+ * protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP,
+ * or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both.
+ * The local listening port number must also be specified in the privatePort parameter.
+ * To just discover the NAT gateway's public IP address, pass zero for protocol,
+ * privatePort, publicPort and ttl.
*
- * fullname: The resource record's full domain name.
+ * privatePort: The port number in network byte order on the local machine which is listening for packets.
*
- * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ * publicPort: The requested public port in network byte order in the NAT gateway that you would
+ * like to map to the private port. Pass 0 if you don't care which public port is chosen for you.
*
- * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ * ttl: The requested renewal period of the NAT port mapping, in seconds.
+ * If the client machine crashes, suffers a power failure, is disconnected from
+ * the network, or suffers some other unfortunate demise which causes it to vanish
+ * unexpectedly without explicitly removing its NAT port mappings, then the NAT gateway
+ * will garbage-collect old stale NAT port mappings when their lifetime expires.
+ * Requesting a short TTL causes such orphaned mappings to be garbage-collected
+ * more promptly, but consumes system resources and network bandwidth with
+ * frequent renewal packets to keep the mapping from expiring.
+ * Requesting a long TTL is more efficient on the network, but in the event of the
+ * client vanishing, stale NAT port mappings will not be garbage-collected as quickly.
+ * Most clients should pass 0 to use a system-wide default value.
*
- * rdlen: The length, in bytes, of the resource record rdata.
+ * callBack: The function to be called when the port mapping request succeeds or fails asynchronously.
*
- * rdata: The raw rdata of the resource record.
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
*
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred.
+ *
+ * If you don't actually want a port mapped, and are just calling the API
+ * because you want to find out the NAT's public IP address (e.g. for UI
+ * display) then pass zero for protocol, privatePort, publicPort and ttl.
*/
-void DNSSD_API DNSServiceReconfirmRecord
+DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
(
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceProtocol protocol, /* TCP and/or UDP */
+ uint16_t privatePort, /* network byte order */
+ uint16_t publicPort, /* network byte order */
+ uint32_t ttl, /* time to live in seconds */
+ DNSServiceNATPortMappingReply callBack,
+ void *context /* may be NULL */
);
* regtype: The service type followed by the protocol, separated by a dot
* (e.g. "_ftp._tcp").
*
- * domain: The domain name, e.g. "apple.com.". Literal dots or backslashes,
+ * domain: The domain name, e.g. "apple.com.". Literal dots or backslashes,
* if any, must be escaped, e.g. "1st\. Floor.apple.com."
*
* return value: Returns 0 on success, -1 on error.
/* TXTRecordRemoveValue()
*
- * Removes a key from a TXTRecordRef. The "key" must be an
+ * Removes a key from a TXTRecordRef. The "key" must be an
* ASCII string which exists in the TXTRecordRef.
*
* txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
* return value: Returns kDNSServiceErr_NoError on success.
* Returns kDNSServiceErr_NoSuchKey if the "key" does not
* exist in the TXTRecordRef.
- *
*/
DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
* which you can pass directly to DNSServiceRegister() or
* to DNSServiceUpdateRecord().
* Returns 0 if the TXTRecordRef is empty.
- *
*/
uint16_t DNSSD_API TXTRecordGetLength
* return value: Returns a pointer to the raw bytes inside the TXTRecordRef
* which you can pass directly to DNSServiceRegister() or
* to DNSServiceUpdateRecord().
- *
*/
const void * DNSSD_API TXTRecordGetBytesPtr
*
* return value: Returns 1 if the TXT Record contains the specified key.
* Otherwise, it returns 0.
- *
*/
int DNSSD_API TXTRecordContainsKey
/* TXTRecordGetCount()
*
- * Returns the number of keys stored in the TXT Record. The count
+ * Returns the number of keys stored in the TXT Record. The count
* can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
*
* txtLen: The size of the received TXT Record.
/* TXTRecordGetItemAtIndex()
*
* Allows you to retrieve a key name and value pointer, given an index into
- * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1.
+ * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1.
* It's also possible to iterate through keys in a TXT record by simply
* calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero
* and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid.
/* DNSServiceSetDefaultDomainForUser()
*
- * Set the default domain for the caller's UID. Future browse and registration
+ * Set the default domain for the caller's UID. Future browse and registration
* calls by this user that do not specify an explicit domain will browse and
- * register in this wide-area domain in addition to .local. In addition, this
+ * register in this wide-area domain in addition to .local. In addition, this
* domain will be returned as a Browse domain via domain enumeration calls.
- *
+ *
*
* Parameters:
*
- * flags: Pass kDNSServiceFlagsAdd to add a domain for a user. Call without
+ * flags: Pass kDNSServiceFlagsAdd to add a domain for a user. Call without
* this flag set to clear a previously added domain.
*
* domain: The domain to be used for the caller's UID.
*
- * return value: Returns kDNSServiceErr_NoError on succeses, otherwise returns
- * an error code indicating the error that occurred
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
+ * an error code indicating the error that occurred.
*/
DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
(
DNSServiceFlags flags,
const char *domain
- );
-
+ );
+
+/* Symbol defined to tell System Configuration Framework where to look in the Dynamic Store
+ * for the list of PrivateDNS domains that need to be handed off to mDNSResponder
+ * (the complete key is "State:/Network/PrivateDNS")
+ */
+#define kDNSServiceCompPrivateDNS "PrivateDNS"
+#define kDNSServiceCompMulticastDNS "MulticastDNS"
+
#endif //__APPLE_API_PRIVATE
-// Some C compiler cleverness. We can make the compiler check certain things for us,
-// and report errors at compile-time if anything is wrong. The usual way to do this would
-// be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but
-// then you don't find out what's wrong until you run the software. This way, if the assertion
-// condition is false, the array size is negative, and the complier complains immediately.
+/* Some C compiler cleverness. We can make the compiler check certain things for us,
+ * and report errors at compile-time if anything is wrong. The usual way to do this would
+ * be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but
+ * then you don't find out what's wrong until you run the software. This way, if the assertion
+ * condition is false, the array size is negative, and the complier complains immediately.
+ */
-struct DNS_SD_CompileTimeAssertionChecks
- {
- char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1];
- };
+struct CompileTimeAssertionChecks_DNS_SD
+ {
+ char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1];
+ };
#ifdef __cplusplus
}
+.\" -*- tab-width: 4 -*-
+.\"
.\" Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
.\"
-.\" @APPLE_LICENSE_HEADER_START@
+.\" Licensed under the Apache License, Version 2.0 (the "License");
+.\" you may not use this file except in compliance with the License.
+.\" You may obtain a copy of the License at
.\"
-.\" This file contains Original Code and/or Modifications of Original Code
-.\" as defined in and that are subject to the Apple Public Source License
-.\" Version 2.0 (the 'License'). You may not use this file except in
-.\" compliance with the License. Please obtain a copy of the License at
-.\" http://www.opensource.apple.com/apsl/ and read it before using this
-.\" file.
+.\" http://www.apache.org/licenses/LICENSE-2.0
.\"
-.\" The Original Code and all software distributed under the License are
-.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-.\" Please see the License for the specific language governing rights and
+.\" Unless required by applicable law or agreed to in writing, software
+.\" distributed under the License is distributed on an "AS IS" BASIS,
+.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+.\" See the License for the specific language governing permissions and
.\" limitations under the License.
-.\"
-.\" @APPLE_LICENSE_HEADER_END@
.\"
.\" $Log: dnsextd.8,v $
+.\" Revision 1.2 2006/08/14 23:24:56 cheshire
+.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+.\"
.\" Revision 1.1 2004/08/15 18:49:18 cheshire
.\" <rdar://problem/3763030> No man page for dnsextd
.\"
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: dnsextd.c,v $
+Revision 1.82 2007/09/27 17:42:49 cheshire
+Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
+
+Revision 1.81 2007/09/21 21:12:37 cheshire
+DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
+
+Revision 1.80 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.79 2007/07/11 02:59:58 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Add AutoTunnel parameter to mDNS_SetSecretForDomain
+
+Revision 1.78 2007/06/20 01:10:13 cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
+
+Revision 1.77 2007/05/15 21:57:17 cheshire
+<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
+assuming that all negative values (or zero!) are invalid socket numbers
+
+Revision 1.76 2007/05/01 23:53:26 cheshire
+<rdar://problem/5175318> dnsextd should refuse updates without attached lease
+
+Revision 1.75 2007/05/01 00:18:12 cheshire
+Use "-launchd" instead of "-d" when starting via launchd
+(-d sets foreground mode, which writes errors to stderr, which is ignored when starting via launchd)
+
+Revision 1.74 2007/04/26 00:35:16 cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
+
+Revision 1.73 2007/04/22 06:02:03 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
+
+Revision 1.72 2007/04/05 22:55:37 cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
+
+Revision 1.71 2007/04/05 19:43:56 cheshire
+Added ProgramName and comment about '-d' option
+
+Revision 1.70 2007/04/05 18:34:40 cheshire
+<rdar://problem/4838930> dnsextd gives "bind - Address already in use" error
+
+Revision 1.69 2007/03/28 21:14:08 cheshire
+The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
+
+Revision 1.68 2007/03/28 18:20:50 cheshire
+Textual tidying
+
+Revision 1.67 2007/03/21 00:30:07 cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
+
+Revision 1.66 2007/03/20 17:07:16 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
+
+Revision 1.65 2007/02/07 19:32:00 cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
+
+Revision 1.64 2007/01/20 01:43:26 cheshire
+<rdar://problem/4058383> Should not write log messages to /dev/console
+
+Revision 1.63 2007/01/20 01:31:56 cheshire
+Update comments
+
+Revision 1.62 2007/01/17 22:06:03 cheshire
+Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
+
+Revision 1.61 2007/01/05 08:30:54 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
+
+Revision 1.60 2007/01/05 08:07:29 cheshire
+Remove unnecessary dummy udsserver_default_reg_domain_changed() routine
+
+Revision 1.59 2007/01/05 05:46:47 cheshire
+Remove unnecessary dummy udsserver_automatic_browse_domain_changed() routine
+
+Revision 1.58 2007/01/04 23:11:54 cheshire
+udsserver_default_browse_domain_changed renamed to udsserver_automatic_browse_domain_changed
+
+Revision 1.57 2007/01/04 01:41:48 cheshire
+Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
+
+Revision 1.56 2006/12/22 20:59:51 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.55 2006/11/30 23:08:39 herscher
+<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
+
+Revision 1.54 2006/11/18 05:01:33 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
+
+Revision 1.53 2006/11/17 23:55:09 cheshire
+<rdar://problem/4842494> dnsextd byte-order bugs on Intel
+
+Revision 1.52 2006/11/17 04:27:51 cheshire
+<rdar://problem/4842494> dnsextd byte-order bugs on Intel
+
+Revision 1.51 2006/11/17 03:50:18 cheshire
+Add debugging loggin in SendPacket and UDPServerTransaction
+
+Revision 1.50 2006/11/17 03:48:57 cheshire
+<rdar://problem/4842493> dnsextd replying on wrong port
+
+Revision 1.49 2006/11/03 06:12:44 herscher
+Make sure all buffers passed to GetRRDisplayString_rdb are of length MaxMsg
+
+Revision 1.48 2006/10/20 19:18:35 cheshire
+<rdar://problem/4669228> dnsextd generates bogus SRV record with null target
+
+Revision 1.47 2006/10/20 05:43:51 herscher
+LookupLLQ() needs to match on the port number when looking up the LLQ
+
+Revision 1.46 2006/10/11 22:56:07 herscher
+Tidy up the implementation of ZoneHandlesName
+
+Revision 1.45 2006/08/22 03:28:57 herscher
+<rdar://problem/4678717> Long-lived queries aren't working well in TOT.
+
+Revision 1.44 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.43 2006/07/20 19:53:33 mkrochma
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+More fixes for private DNS
+
+Revision 1.42 2006/07/05 22:48:19 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+
+*/
+
+#include "dnsextd.h"
+#include "../mDNSShared/uds_daemon.h"
+#include "../mDNSShared/dnssd_ipc.h"
+#include "../mDNSCore/uDNS.h"
+#include "../mDNSShared/DebugServices.h"
+#include <signal.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <time.h>
+#include <errno.h>
+
+// Compatibility workaround
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
+//
+// Constants
+//
+mDNSexport const char ProgramName[] = "dnsextd";
+
+#define LOOPBACK "127.0.0.1"
+#if !defined(LISTENQ)
+# define LISTENQ 128 // tcp connection backlog
+#endif
+#define RECV_BUFLEN 9000
+#define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
+#define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
+#define SRV_TTL 7200 // TTL For _dns-update SRV records
+#define CONFIG_FILE "/etc/dnsextd.conf"
+#define TCP_SOCKET_FLAGS kTCPSocketFlags_UseTLS
+
+// LLQ Lease bounds (seconds)
+#define LLQ_MIN_LEASE (15 * 60)
+#define LLQ_MAX_LEASE (120 * 60)
+#define LLQ_LEASE_FUDGE 60
+
+// LLQ SOA poll interval (microseconds)
+#define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
+#define LLQ_MONITOR_INTERVAL 250000
+#ifdef SIGINFO
+#define INFO_SIGNAL SIGINFO
+#else
+#define INFO_SIGNAL SIGUSR1
+#endif
+
+#define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
+
+//
+// Data Structures
+// Structs/fields that must be locked for thread safety are explicitly commented
+//
+
+// args passed to UDP request handler thread as void*
+
+typedef struct
+ {
+ PktMsg pkt;
+ struct sockaddr_in cliaddr;
+ DaemonInfo *d;
+ int sd;
+ } UDPContext;
+
+// args passed to TCP request handler thread as void*
+typedef struct
+ {
+ PktMsg pkt;
+ struct sockaddr_in cliaddr;
+ TCPSocket *sock; // socket connected to client
+ DaemonInfo *d;
+ } TCPContext;
+
+// args passed to UpdateAnswerList thread as void*
+typedef struct
+ {
+ DaemonInfo *d;
+ AnswerListElem *a;
+ } UpdateAnswerListArgs;
+
+//
+// Global Variables
+//
+
+// booleans to determine runtime output
+// read-only after initialization (no mutex protection)
+static mDNSBool foreground = 0;
+static mDNSBool verbose = 0;
+
+// globals set via signal handler (accessed exclusively by main select loop and signal handler)
+static mDNSBool terminate = 0;
+static mDNSBool dumptable = 0;
+static mDNSBool hangup = 0;
+
+// global for config file location
+static char * cfgfile = NULL;
+
+//
+// Logging Routines
+// Log messages are delivered to syslog unless -f option specified
+//
+
+// common message logging subroutine
+mDNSlocal void PrintLog(const char *buffer)
+ {
+ if (foreground)
+ {
+ fprintf(stderr,"%s\n", buffer);
+ fflush(stderr);
+ }
+ else
+ {
+ openlog("dnsextd", LOG_CONS, LOG_DAEMON);
+ syslog(LOG_ERR, "%s", buffer);
+ closelog();
+ }
+ }
+
+// Verbose Logging (conditional on -v option)
+mDNSlocal void VLog(const char *format, ...)
+ {
+ char buffer[512];
+ va_list ptr;
+
+ if (!verbose) return;
+ va_start(ptr,format);
+ buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+ va_end(ptr);
+ PrintLog(buffer);
+ }
+
+// Unconditional Logging
+mDNSlocal void Log(const char *format, ...)
+ {
+ char buffer[512];
+ va_list ptr;
+
+ va_start(ptr,format);
+ buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+ va_end(ptr);
+ PrintLog(buffer);
+ }
+
+// Error Logging
+// prints message "dnsextd <function>: <operation> - <error message>"
+// must be compiled w/ -D_REENTRANT for thread-safe errno usage
+mDNSlocal void LogErr(const char *fn, const char *operation)
+ {
+ char buf[512], errbuf[256];
+ strerror_r(errno, errbuf, sizeof(errbuf));
+ snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, errbuf);
+ PrintLog(buf);
+ }
+
+//
+// Networking Utility Routines
+//
+
+// Convert DNS Message Header from Network to Host byte order
+mDNSlocal void HdrNToH(PktMsg *pkt)
+ {
+ // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
+ mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
+ pkt->msg.h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+ pkt->msg.h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
+ pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
+ pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
+ }
+
+// Convert DNS Message Header from Host to Network byte order
+mDNSlocal void HdrHToN(PktMsg *pkt)
+ {
+ mDNSu16 numQuestions = pkt->msg.h.numQuestions;
+ mDNSu16 numAnswers = pkt->msg.h.numAnswers;
+ mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
+ mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
+ mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
+
+ // Put all the integer values in IETF byte-order (MSB first, LSB second)
+ *ptr++ = (mDNSu8)(numQuestions >> 8);
+ *ptr++ = (mDNSu8)(numQuestions & 0xFF);
+ *ptr++ = (mDNSu8)(numAnswers >> 8);
+ *ptr++ = (mDNSu8)(numAnswers & 0xFF);
+ *ptr++ = (mDNSu8)(numAuthorities >> 8);
+ *ptr++ = (mDNSu8)(numAuthorities & 0xFF);
+ *ptr++ = (mDNSu8)(numAdditionals >> 8);
+ *ptr++ = (mDNSu8)(numAdditionals & 0xFF);
+ }
+
+
+// Add socket to event loop
+
+mDNSlocal mStatus AddSourceToEventLoop( DaemonInfo * self, TCPSocket *sock, EventCallback callback, void *context )
+ {
+ EventSource * newSource;
+ mStatus err = mStatus_NoError;
+
+ if ( self->eventSources.LinkOffset == 0 )
+ {
+ InitLinkedList( &self->eventSources, offsetof( EventSource, next));
+ }
+
+ newSource = ( EventSource*) malloc( sizeof *newSource );
+ if ( newSource == NULL )
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+
+ newSource->callback = callback;
+ newSource->context = context;
+ newSource->sock = sock;
+ newSource->fd = mDNSPlatformTCPGetFD( sock );
+
+ AddToTail( &self->eventSources, newSource );
+
+exit:
+
+ return err;
+ }
+
+
+// Remove socket from event loop
+
+mDNSlocal mStatus RemoveSourceFromEventLoop( DaemonInfo * self, TCPSocket *sock )
+ {
+ EventSource * source;
+ mStatus err;
+
+ for ( source = ( EventSource* ) self->eventSources.Head; source; source = source->next )
+ {
+ if ( source->sock == sock )
+ {
+ RemoveFromList( &self->eventSources, source );
+
+ free( source );
+ err = mStatus_NoError;
+ goto exit;
+ }
+ }
+
+ err = mStatus_NoSuchNameErr;
+
+exit:
+
+ return err;
+ }
+
+// create a socket connected to nameserver
+// caller terminates connection via close()
+mDNSlocal TCPSocket *ConnectToServer(DaemonInfo *d)
+ {
+ int ntries = 0, retry = 0;
+
+ while (1)
+ {
+ mDNSIPPort port = zeroIPPort;
+ int fd;
+
+ TCPSocket *sock = mDNSPlatformTCPSocket( NULL, 0, &port );
+ if ( !sock ) { LogErr("ConnectToServer", "socket"); return NULL; }
+ fd = mDNSPlatformTCPGetFD( sock );
+ if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
+ mDNSPlatformTCPCloseConnection( sock );
+ if (++ntries < 10)
+ {
+ LogErr("ConnectToServer", "connect");
+ Log("ConnectToServer - retrying connection");
+ if (!retry) retry = 500000 + random() % 500000;
+ usleep(retry);
+ retry *= 2;
+ }
+ else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries); return NULL; }
+ }
+ }
+
+// send an entire block of data over a connected socket
+mDNSlocal int MySend(TCPSocket *sock, const void *msg, int len)
+ {
+ int selectval, n, nsent = 0;
+ fd_set wset;
+ struct timeval timeout = { 3, 0 }; // until we remove all calls from main thread, keep timeout short
+
+ while (nsent < len)
+ {
+ int fd;
+
+ FD_ZERO(&wset);
+
+ fd = mDNSPlatformTCPGetFD( sock );
+
+ FD_SET( fd, &wset );
+ selectval = select( fd+1, NULL, &wset, NULL, &timeout);
+ if (selectval < 0) { LogErr("MySend", "select"); return -1; }
+ if (!selectval || !FD_ISSET(fd, &wset)) { Log("MySend - timeout"); return -1; }
+
+ n = mDNSPlatformWriteTCP( sock, ( char* ) msg + nsent, len - nsent);
+
+ if (n < 0) { LogErr("MySend", "send"); return -1; }
+ nsent += n;
+ }
+ return 0;
+ }
+
+// Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
+mDNSlocal int SendPacket(TCPSocket *sock, PktMsg *pkt)
+ {
+ // send the lenth, in network byte order
+ mDNSu16 len = htons((mDNSu16)pkt->len);
+ if (MySend(sock, &len, sizeof(len)) < 0) return -1;
+
+ // send the message
+ VLog("SendPacket Q:%d A:%d A:%d A:%d ",
+ ntohs(pkt->msg.h.numQuestions),
+ ntohs(pkt->msg.h.numAnswers),
+ ntohs(pkt->msg.h.numAuthorities),
+ ntohs(pkt->msg.h.numAdditionals));
+ return MySend(sock, &pkt->msg, pkt->len);
+ }
+
+// Receive len bytes, waiting until we have all of them.
+// Returns number of bytes read (which should always be the number asked for).
+static int my_recv(TCPSocket *sock, void *const buf, const int len, mDNSBool * closed)
+ {
+ // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
+ // use an explicit while() loop instead.
+ // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
+ // arithmetic on "void *" pointers is compiler-dependent.
+
+ fd_set rset;
+ struct timeval timeout = { 3, 0 }; // until we remove all calls from main thread, keep timeout short
+ int selectval, remaining = len;
+ char *ptr = (char *)buf;
+ ssize_t num_read;
+
+ while (remaining)
+ {
+ int fd;
+
+ fd = mDNSPlatformTCPGetFD( sock );
+
+ FD_ZERO(&rset);
+ FD_SET(fd, &rset);
+ selectval = select(fd+1, &rset, NULL, NULL, &timeout);
+ if (selectval < 0) { LogErr("my_recv", "select"); return -1; }
+ if (!selectval || !FD_ISSET(fd, &rset))
+ {
+ Log("my_recv - timeout");
+ return -1;
+ }
+
+ num_read = mDNSPlatformReadTCP( sock, ptr, remaining, closed );
+
+ if (((num_read == 0) && *closed) || (num_read < 0) || (num_read > remaining)) return -1;
+ if (num_read == 0) return 0;
+ ptr += num_read;
+ remaining -= num_read;
+ }
+ return(len);
+ }
+
+// Return a DNS Message read off of a TCP socket, or NULL on failure
+// If storage is non-null, result is placed in that buffer. Otherwise,
+// returned value is allocated with Malloc, and contains sufficient extra
+// storage for a Lease OPT RR
+
+mDNSlocal PktMsg*
+RecvPacket
+ (
+ TCPSocket * sock,
+ PktMsg * storage,
+ mDNSBool * closed
+ )
+ {
+ int nread;
+ int allocsize;
+ mDNSu16 msglen = 0;
+ PktMsg * pkt = NULL;
+ unsigned int srclen;
+ int fd;
+ mStatus err = 0;
+
+ fd = mDNSPlatformTCPGetFD( sock );
+
+ nread = my_recv( sock, &msglen, sizeof( msglen ), closed );
+
+ require_action_quiet( nread != -1, exit, err = mStatus_UnknownErr );
+ require_action_quiet( nread > 0, exit, err = mStatus_NoError );
+
+ msglen = ntohs( msglen );
+ require_action_quiet( nread == sizeof( msglen ), exit, err = mStatus_UnknownErr; Log( "Could not read length field of message") );
+
+ if ( storage )
+ {
+ require_action_quiet( msglen <= sizeof( storage->msg ), exit, err = mStatus_UnknownErr; Log( "RecvPacket: provided buffer too small." ) );
+ pkt = storage;
+ }
+ else
+ {
+ // buffer extra space to add an OPT RR
+
+ if ( msglen > sizeof(DNSMessage))
+ {
+ allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
+ }
+ else
+ {
+ allocsize = sizeof(PktMsg);
+ }
+
+ pkt = malloc(allocsize);
+ require_action_quiet( pkt, exit, err = mStatus_NoMemoryErr; LogErr( "RecvPacket", "malloc" ) );
+ bzero( pkt, sizeof( *pkt ) );
+ }
+
+ pkt->len = msglen;
+ srclen = sizeof(pkt->src);
+
+ if ( getpeername( fd, ( struct sockaddr* ) &pkt->src, &srclen ) || ( srclen != sizeof( pkt->src ) ) )
+ {
+ LogErr("RecvPacket", "getpeername");
+ bzero(&pkt->src, sizeof(pkt->src));
+ }
+
+ nread = my_recv(sock, &pkt->msg, msglen, closed );
+ require_action_quiet( nread >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvPacket", "recv" ) );
+ require_action_quiet( nread == msglen, exit, err = mStatus_UnknownErr ; Log( "Could not read entire message" ) );
+ require_action_quiet( pkt->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr ; Log( "RecvPacket: Message too short (%d bytes)", pkt->len ) );
+
+exit:
+
+ if ( err && pkt )
+ {
+ if ( pkt != storage )
+ {
+ free(pkt);
+ }
+
+ pkt = NULL;
+ }
+
+ return pkt;
+ }
+
+
+mDNSlocal DNSZone*
+FindZone
+ (
+ DaemonInfo * self,
+ domainname * name
+ )
+ {
+ DNSZone * zone;
+
+ for ( zone = self->zones; zone; zone = zone->next )
+ {
+ if ( SameDomainName( &zone->name, name ) )
+ {
+ break;
+ }
+ }
+
+ return zone;
+ }
+
+
+mDNSlocal mDNSBool
+ZoneHandlesName
+ (
+ const domainname * zname,
+ const domainname * dname
+ )
+ {
+ mDNSu16 i = DomainNameLength( zname );
+ mDNSu16 j = DomainNameLength( dname );
+
+ if ( ( i == ( MAX_DOMAIN_NAME + 1 ) ) || ( j == ( MAX_DOMAIN_NAME + 1 ) ) || ( i > j ) || ( memcmp( zname->c, dname->c + ( j - i ), i ) != 0 ) )
+ {
+ return mDNSfalse;
+ }
+
+ return mDNStrue;
+ }
+
+
+mDNSlocal mDNSBool IsQuery( PktMsg * pkt )
+ {
+ return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery );
+ }
+
+
+mDNSlocal mDNSBool IsUpdate( PktMsg * pkt )
+ {
+ return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_OP_Update );
+ }
+
+
+mDNSlocal mDNSBool IsNotify(PktMsg *pkt)
+ {
+ return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( mDNSu8) ( kDNSFlag0_OP_Notify );
+ }
+
+
+mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
+ {
+ const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
+ LargeCacheRecord lcr;
+ int i;
+ mDNSBool result = mDNSfalse;
+
+ HdrNToH(pkt);
+ if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
+
+ if (!pkt->msg.h.numAdditionals) goto end;
+ ptr = LocateAdditionals(&pkt->msg, end);
+ if (!ptr) goto end;
+
+ // find last Additional info.
+ for (i = 0; i < pkt->msg.h.numAdditionals; i++)
+ {
+ ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
+ if (!ptr) { Log("Unable to read additional record"); goto end; }
+ }
+
+ if ( lcr.r.resrec.rrtype == kDNSType_OPT && lcr.r.resrec.rdlength >= LLQ_OPT_RDLEN && lcr.r.resrec.rdata->u.opt.opt == kDNSOpt_LLQ )
+ {
+ result = mDNStrue;
+ }
+
+ end:
+ HdrHToN(pkt);
+ return result;
+ }
+
+// !!!KRS implement properly
+mDNSlocal mDNSBool IsLLQAck(PktMsg *pkt)
+ {
+ if ((pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery ) &&
+ pkt->msg.h.numQuestions && !pkt->msg.h.numAnswers && !pkt->msg.h.numAuthorities) return mDNStrue;
+ return mDNSfalse;
+ }
+
+
+mDNSlocal mDNSBool
+IsPublicSRV
+ (
+ DaemonInfo * self,
+ DNSQuestion * q
+ )
+ {
+ DNameListElem * elem;
+ mDNSBool ret = mDNSfalse;
+ int i = ( int ) DomainNameLength( &q->qname ) - 1;
+
+ for ( elem = self->public_names; elem; elem = elem->next )
+ {
+ int j = ( int ) DomainNameLength( &elem->name ) - 1;
+
+ if ( i > j )
+ {
+ for ( ; i >= 0; i--, j-- )
+ {
+ if ( q->qname.c[ i ] != elem->name.c[ j ] )
+ {
+ ret = mDNStrue;
+ goto exit;
+ }
+ }
+ }
+ }
+
+exit:
+
+ return ret;
+ }
+
+
+mDNSlocal void
+SetZone
+ (
+ DaemonInfo * self,
+ PktMsg * pkt
+ )
+ {
+ domainname zname;
+ mDNSu8 QR_OP;
+ const mDNSu8 * ptr = pkt->msg.data;
+ mDNSBool exception = mDNSfalse;
+
+ // Initialize
+
+ pkt->zone = NULL;
+ pkt->isZonePublic = mDNStrue;
+ zname.c[0] = '\0';
+
+ // Figure out what type of packet this is
+
+ QR_OP = ( mDNSu8 ) ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask );
+
+ if ( IsQuery( pkt ) )
+ {
+ DNSQuestion question;
+
+ // It's a query
+
+ ptr = getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
+
+ AppendDomainName( &zname, &question.qname );
+
+ exception = ( ( question.qtype == kDNSType_SOA ) || ( question.qtype == kDNSType_NS ) || ( ( question.qtype == kDNSType_SRV ) && IsPublicSRV( self, &question ) ) );
+ }
+ else if ( IsUpdate( pkt ) )
+ {
+ DNSQuestion question;
+
+ // It's an update. The format of the zone section is the same as the format for the question section
+ // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
+
+ ptr = getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
+
+ AppendDomainName( &zname, &question.qname );
+
+ exception = mDNSfalse;
+ }
+
+ if ( zname.c[0] != '\0' )
+ {
+ // Find the right zone
+
+ for ( pkt->zone = self->zones; pkt->zone; pkt->zone = pkt->zone->next )
+ {
+ if ( ZoneHandlesName( &pkt->zone->name, &zname ) )
+ {
+ VLog( "found correct zone %##s for query", pkt->zone->name.c );
+
+ pkt->isZonePublic = ( ( pkt->zone->type == kDNSZonePublic ) || exception );
+
+ VLog( "zone %##s is %s", pkt->zone->name.c, ( pkt->isZonePublic ) ? "public" : "private" );
+
+ break;
+ }
+ }
+ }
+ }
+
+
+mDNSlocal int
+UDPServerTransaction(const DaemonInfo *d, const PktMsg *request, PktMsg *reply, mDNSBool *trunc)
+ {
+ fd_set rset;
+ struct timeval timeout = { 3, 0 }; // until we remove all calls from main thread, keep timeout short
+ int sd;
+ int res;
+ mStatus err = mStatus_NoError;
+
+ // Initialize
+
+ *trunc = mDNSfalse;
+
+ // Create a socket
+
+ sd = socket( AF_INET, SOCK_DGRAM, 0 );
+ require_action( sd >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "socket" ) );
+
+ // Send the packet to the nameserver
+
+ VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
+ ntohs(request->msg.h.numQuestions),
+ ntohs(request->msg.h.numAnswers),
+ ntohs(request->msg.h.numAuthorities),
+ ntohs(request->msg.h.numAdditionals));
+ res = sendto( sd, (char *)&request->msg, request->len, 0, ( struct sockaddr* ) &d->ns_addr, sizeof( d->ns_addr ) );
+ require_action( res == (int) request->len, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "sendto" ) );
+
+ // Wait for reply
+
+ FD_ZERO( &rset );
+ FD_SET( sd, &rset );
+ res = select( sd + 1, &rset, NULL, NULL, &timeout );
+ require_action( res >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "select" ) );
+ require_action( ( res > 0 ) && FD_ISSET( sd, &rset ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - timeout" ) );
+
+ // Receive reply
+
+ reply->len = recvfrom( sd, &reply->msg, sizeof(reply->msg), 0, NULL, NULL );
+ require_action( ( ( int ) reply->len ) >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "recvfrom" ) );
+ require_action( reply->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - Message too short (%d bytes)", reply->len ) );
+
+ // Check for truncation bit
+
+ if ( reply->msg.h.flags.b[0] & kDNSFlag0_TC )
+ {
+ *trunc = mDNStrue;
+ }
+
+exit:
+
+ if ( sd >= 0 )
+ {
+ close( sd );
+ }
+
+ return err;
+ }
+
+//
+// Dynamic Update Utility Routines
+//
+
+// check if a request and server response complete a successful dynamic update
+mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
+ {
+ char buf[32];
+ char *vlogmsg = NULL;
+
+ // check messages
+ if (!request || !reply) { vlogmsg = "NULL message"; goto failure; }
+ if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; }
+
+ // check request operation
+ if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask))
+ { vlogmsg = "Request opcode not an update"; goto failure; }
+
+ // check result
+ if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask)) { vlogmsg = "Reply contains non-zero rcode"; goto failure; }
+ if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response))
+ { vlogmsg = "Reply opcode not an update response"; goto failure; }
+
+ VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32));
+ return mDNStrue;
+
+ failure:
+ VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg);
+ return mDNSfalse;
+ }
+
+// Allocate an appropriately sized CacheRecord and copy data from original.
+// Name pointer in CacheRecord object is set to point to the name specified
+//
+mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name)
+ {
+ CacheRecord *cr;
+ size_t size = sizeof(*cr);
+ if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize;
+ cr = malloc(size);
+ if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
+ memcpy(cr, orig, size);
+ cr->resrec.rdata = (RData*)&cr->rdatastorage;
+ cr->resrec.name = name;
+
+ return cr;
+ }
+
+
+//
+// Lease Hashtable Utility Routines
+//
+
+// double hash table size
+// caller must lock table prior to invocation
+mDNSlocal void RehashTable(DaemonInfo *d)
+ {
+ RRTableElem *ptr, *tmp, **new;
+ int i, bucket, newnbuckets = d->nbuckets * 2;
+
+ VLog("Rehashing lease table (new size %d buckets)", newnbuckets);
+ new = malloc(sizeof(RRTableElem *) * newnbuckets);
+ if (!new) { LogErr("RehashTable", "malloc"); return; }
+ bzero(new, newnbuckets * sizeof(RRTableElem *));
+
+ for (i = 0; i < d->nbuckets; i++)
+ {
+ ptr = d->table[i];
+ while (ptr)
+ {
+ bucket = ptr->rr.resrec.namehash % newnbuckets;
+ tmp = ptr;
+ ptr = ptr->next;
+ tmp->next = new[bucket];
+ new[bucket] = tmp;
+ }
+ }
+ d->nbuckets = newnbuckets;
+ free(d->table);
+ d->table = new;
+ }
+
+// print entire contents of hashtable, invoked via SIGINFO
+mDNSlocal void PrintLeaseTable(DaemonInfo *d)
+ {
+ int i;
+ RRTableElem *ptr;
+ char rrbuf[MaxMsg], addrbuf[16];
+ struct timeval now;
+ int hr, min, sec;
+
+ if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; }
+ if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
+
+ Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems);
+ for (i = 0; i < d->nbuckets; i++)
+ {
+ for (ptr = d->table[i]; ptr; ptr = ptr->next)
+ {
+ hr = ((ptr->expire - now.tv_sec) / 60) / 60;
+ min = ((ptr->expire - now.tv_sec) / 60) % 60;
+ sec = (ptr->expire - now.tv_sec) % 60;
+ Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET, &ptr->cli.sin_addr, addrbuf, 16), hr, min, sec,
+ GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf));
+ }
+ }
+ pthread_mutex_unlock(&d->tablelock);
+ }
+
+//
+// Startup SRV Registration Routines
+// Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
+// the daemon accepts requests
+//
+
+// delete all RRS of a given name/type
+mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit, ResourceRecord *rr)
+ {
+ ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
+ if (!ptr || ptr + 10 >= limit) return NULL; // out of space
+ ptr[0] = (mDNSu8)(rr->rrtype >> 8);
+ ptr[1] = (mDNSu8)(rr->rrtype & 0xFF);
+ ptr[2] = (mDNSu8)((mDNSu16)kDNSQClass_ANY >> 8);
+ ptr[3] = (mDNSu8)((mDNSu16)kDNSQClass_ANY & 0xFF);
+ bzero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata
+ msg->h.mDNS_numUpdates++;
+ return ptr + 10;
+ }
+
+mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, DNSZone * zone, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSIPPort port, mDNSBool registration)
+ {
+ AuthRecord rr;
+ char hostname[1024], buf[MaxMsg];
+ mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage);
+
+ ( void ) d;
+
+ mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, NULL, NULL);
+ rr.resrec.rrclass = kDNSClass_IN;
+ rr.resrec.rdata->u.srv.priority = 0;
+ rr.resrec.rdata->u.srv.weight = 0;
+ rr.resrec.rdata->u.srv.port = port;
+ if (gethostname(hostname, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
+ rr.resrec.rdata->u.srv.target.c[0] = '\0';
+
+ MakeDomainNameFromDNSNameString(&rr.namestorage, regtype);
+ AppendDomainName(&rr.namestorage, &zone->name);
+ VLog("%s %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
+ GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
+ if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
+ else ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec);
+ return ptr;
+ }
+
+
+// perform dynamic update.
+// specify deletion by passing false for the register parameter, otherwise register the records.
+mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
+ {
+ TCPSocket *sock = NULL;
+ DNSZone * zone;
+ int err = mStatus_NoError;
+
+ sock = ConnectToServer( d );
+ require_action( sock, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: ConnectToServer failed" ) );
+
+ for ( zone = d->zones; zone; zone = zone->next )
+ {
+ PktMsg pkt;
+ mDNSu8 *ptr = pkt.msg.data;
+ mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
+ PktMsg *reply = NULL;
+ mDNSBool closed;
+ mDNSBool ok;
+
+ // Initialize message
+ InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
+ pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
+ pkt.src.sin_family = AF_INET;
+
+ // format message body
+ ptr = putZone(&pkt.msg, ptr, end, &zone->name, mDNSOpaque16fromIntVal(kDNSClass_IN));
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+
+ if ( zone->type == kDNSZonePrivate )
+ {
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls._tcp.", d->private_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls._tcp.", d->private_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls._tcp.", d->private_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+
+ if ( !registration )
+ {
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ }
+ }
+ else
+ {
+ if ( !registration )
+ {
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls.", d->private_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls.", d->private_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls.", d->private_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ }
+
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
+ require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
+ }
+
+ HdrHToN(&pkt);
+
+ if ( zone->updateKeys )
+ {
+ ptr = DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 );
+ require_action( ptr, exit, Log("UpdateSRV: Error constructing lease expiration update" ) );
+ }
+
+ pkt.len = ptr - (mDNSu8 *)&pkt.msg;
+
+ // send message, receive reply
+
+ err = SendPacket( sock, &pkt );
+ require_action( !err, exit, Log( "UpdateSRV: SendPacket failed" ) );
+
+ reply = RecvPacket( sock, NULL, &closed );
+ require_action( reply, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: RecvPacket returned NULL" ) );
+
+ ok = SuccessfulUpdateTransaction( &pkt, reply );
+
+ if ( !ok )
+ {
+ Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
+ }
+
+ free( reply );
+ }
+
+exit:
+
+ if ( sock )
+ {
+ mDNSPlatformTCPCloseConnection( sock );
+ }
+
+ return err;
+ }
+
+// wrapper routines/macros
+#define ClearUpdateSRV(d) UpdateSRV(d, 0)
+
+// clear any existing records prior to registration
+mDNSlocal int SetUpdateSRV(DaemonInfo *d)
+ {
+ int err;
+
+ err = ClearUpdateSRV(d); // clear any existing record
+ if (!err) err = UpdateSRV(d, 1);
+ return err;
+ }
+
+//
+// Argument Parsing and Configuration
+//
+
+mDNSlocal void PrintUsage(void)
+ {
+ fprintf(stderr, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
+ "Use \"dnsextd -h\" for help\n");
+ }
+
+mDNSlocal void PrintHelp(void)
+ {
+ fprintf(stderr, "\n\n");
+ PrintUsage();
+
+ fprintf(stderr,
+ "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
+ "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
+ "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
+ "Discovery, Update Leases, and Long Lived Queries.)\n\n"
+
+ "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
+ "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
+ "primary master server for this zone.\n\n"
+
+ "The options are as follows:\n\n"
+
+ "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
+
+ "-d Run daemon in foreground.\n\n"
+
+ "-h Print help.\n\n"
+
+ "-v Verbose output.\n\n"
+ );
+ }
+
+
+// Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
+// returns 0 (success) if program is to continue execution
+// output control arguments (-f, -v) do not affect this routine
+mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
+ {
+ DNSZone * zone;
+ int opt;
+ int err = 0;
+
+ cfgfile = strdup( CONFIG_FILE );
+ require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr );
+
+ // defaults, may be overriden by command option
+
+ // setup our sockaddr
+
+ bzero( &d->addr, sizeof( d->addr ) );
+ d->addr.sin_addr.s_addr = zerov4Addr.NotAnInteger;
+ d->addr.sin_port = UnicastDNSPort.NotAnInteger;
+ d->addr.sin_family = AF_INET;
+#ifndef NOT_HAVE_SA_LEN
+ d->addr.sin_len = sizeof( d->addr );
+#endif
+
+ // setup nameserver's sockaddr
+
+ bzero(&d->ns_addr, sizeof(d->ns_addr));
+ d->ns_addr.sin_family = AF_INET;
+ inet_pton( AF_INET, LOOPBACK, &d->ns_addr.sin_addr );
+ d->ns_addr.sin_port = NSIPCPort.NotAnInteger;
+#ifndef NOT_HAVE_SA_LEN
+ d->ns_addr.sin_len = sizeof( d->ns_addr );
+#endif
+
+ // setup our ports
+
+ d->private_port = PrivateDNSPort;
+ d->llq_port = DNSEXTPort;
+
+ while ((opt = getopt(argc, argv, "f:hdv")) != -1)
+ {
+ switch(opt)
+ {
+ case 'f': free( cfgfile ); cfgfile = strdup( optarg ); require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr ); break;
+ case 'h': PrintHelp(); return -1;
+ case 'd': foreground = 1; break; // Also used when launched via OS X's launchd mechanism
+ case 'v': verbose = 1; break;
+ default: goto arg_error;
+ }
+ }
+
+ err = ParseConfig( d, cfgfile );
+ require_noerr( err, arg_error );
+
+ // Make sure we've specified some zones
+
+ require_action( d->zones, arg_error, err = mStatus_UnknownErr );
+
+ // if we have a shared secret, use it for the entire zone
+
+ for ( zone = d->zones; zone; zone = zone->next )
+ {
+ if ( zone->updateKeys )
+ {
+ AssignDomainName( &zone->updateKeys->domain, &zone->name );
+ }
+ }
+
+ return 0;
+
+arg_error:
+
+ PrintUsage();
+ return -1;
+ }
+
+
+//
+// Initialization Routines
+//
+
+// Allocate memory, initialize locks and bookkeeping variables
+mDNSlocal int InitLeaseTable(DaemonInfo *d)
+ {
+ if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
+ d->nbuckets = LEASETABLE_INIT_NBUCKETS;
+ d->nelems = 0;
+ d->table = malloc(sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
+ if (!d->table) { LogErr("InitLeaseTable", "malloc"); return -1; }
+ bzero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
+ return 0;
+ }
+
+
+mDNSlocal int
+SetupSockets
+ (
+ DaemonInfo * self
+ )
+ {
+ static const int kOn = 1;
+ int sockpair[2];
+ mDNSBool private = mDNSfalse;
+ struct sockaddr_in daddr;
+ DNSZone * zone;
+ mStatus err = 0;
+
+ // set up sockets on which we all ns requests
+
+ self->tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
+ require_action( dnssd_SocketValid(self->tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+ err = setsockopt(self->tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+ require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
+#endif
+
+ err = bind( self->tcpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
+ require_action( !err, exit, LogErr( "SetupSockets", "bind self->tcpsd" ) );
+
+ err = listen( self->tcpsd, LISTENQ );
+ require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
+
+ self->udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
+ require_action( dnssd_SocketValid(self->udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+ err = setsockopt(self->udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+ require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
+#endif
+
+ err = bind( self->udpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
+ require_action( !err, exit, LogErr( "SetupSockets", "bind self->udpsd" ) );
+
+ // set up sockets on which we receive llq requests
+
+ bzero(&self->llq_addr, sizeof(self->llq_addr));
+ self->llq_addr.sin_family = AF_INET;
+ self->llq_addr.sin_addr.s_addr = zerov4Addr.NotAnInteger;
+ self->llq_addr.sin_port = ( self->llq_port.NotAnInteger ) ? self->llq_port.NotAnInteger : DNSEXTPort.NotAnInteger;
+
+ self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
+ require_action( dnssd_SocketValid(self->llq_tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+ err = setsockopt(self->llq_tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+ require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
+#endif
+
+ err = bind( self->llq_tcpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
+ require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
+
+ err = listen( self->llq_tcpsd, LISTENQ );
+ require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
+
+ self->llq_udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
+ require_action( dnssd_SocketValid(self->llq_udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+ err = setsockopt(self->llq_udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+ require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
+#endif
+
+ err = bind(self->llq_udpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
+ require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
+
+ // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
+
+ err = socketpair( AF_LOCAL, SOCK_STREAM, 0, sockpair );
+ require_action( !err, exit, LogErr( "SetupSockets", "socketpair" ) );
+
+ self->LLQEventListenSock = sockpair[0];
+ self->LLQEventNotifySock = sockpair[1];
+
+ // set up socket on which we receive private requests
+
+ self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
+ require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+ bzero(&daddr, sizeof(daddr));
+ daddr.sin_family = AF_INET;
+ daddr.sin_addr.s_addr = zerov4Addr.NotAnInteger;
+ daddr.sin_port = ( self->private_port.NotAnInteger ) ? self->private_port.NotAnInteger : PrivateDNSPort.NotAnInteger;
+
+ self->tlssd = socket( AF_INET, SOCK_STREAM, 0 );
+ require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+
+#if defined(SO_REUSEADDR)
+ err = setsockopt(self->tlssd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+ require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
+#endif
+
+ err = bind( self->tlssd, ( struct sockaddr* ) &daddr, sizeof( daddr ) );
+ require_action( !err, exit, LogErr( "SetupSockets", "bind self->tlssd" ) );
+
+ err = listen( self->tlssd, LISTENQ );
+ require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
+
+ // Do we have any private zones?
+
+ for ( zone = self->zones; zone; zone = zone->next )
+ {
+ if ( zone->type == kDNSZonePrivate )
+ {
+ private = mDNStrue;
+ break;
+ }
+ }
+
+ if ( private )
+ {
+ err = mDNSPlatformTLSSetupCerts();
+ require_action( !err, exit, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
+ }
+
+exit:
+
+ return err;
+ }
+
+//
+// periodic table updates
+//
+
+// Delete a resource record from the nameserver via a dynamic update
+// sd is a socket already connected to the server
+mDNSlocal void DeleteOneRecord(DaemonInfo *d, CacheRecord *rr, domainname *zname, TCPSocket *sock)
+ {
+ DNSZone * zone;
+ PktMsg pkt;
+ mDNSu8 *ptr = pkt.msg.data;
+ mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
+ char buf[MaxMsg];
+ mDNSBool closed;
+ PktMsg *reply = NULL;
+
+ VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf));
+
+ InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
+
+ ptr = putZone(&pkt.msg, ptr, end, zname, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+ if (!ptr) goto end;
+ ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec);
+ if (!ptr) goto end;
+
+ HdrHToN(&pkt);
+
+ zone = FindZone( d, zname );
+
+ if ( zone && zone->updateKeys)
+ {
+ ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 );
+ if (!ptr) goto end;
+ }
+
+ pkt.len = ptr - (mDNSu8 *)&pkt.msg;
+ pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
+ pkt.src.sin_family = AF_INET;
+ if (SendPacket( sock, &pkt)) { Log("DeleteOneRecord: SendPacket failed"); }
+ reply = RecvPacket( sock, NULL, &closed );
+ if (reply) HdrNToH(reply);
+ require_action( reply, end, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
+
+ if (!SuccessfulUpdateTransaction(&pkt, reply))
+ Log("Expiration update failed with rcode %d", reply ? reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask : -1);
+
+ end:
+ if (!ptr) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
+ if (reply) free(reply);
+ }
+
+// iterate over table, deleting expired records (or all records if DeleteAll is true)
+mDNSlocal void DeleteRecords(DaemonInfo *d, mDNSBool DeleteAll)
+ {
+ struct timeval now;
+ int i;
+ TCPSocket *sock = ConnectToServer(d);
+ if (!sock) { Log("DeleteRecords: ConnectToServer failed"); return; }
+ if (gettimeofday(&now, NULL)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
+ if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
+
+ for (i = 0; i < d->nbuckets; i++)
+ {
+ RRTableElem **ptr = &d->table[i];
+ while (*ptr)
+ {
+ if (DeleteAll || (*ptr)->expire - now.tv_sec < 0)
+ {
+ RRTableElem *fptr;
+ // delete record from server
+ DeleteOneRecord(d, &(*ptr)->rr, &(*ptr)->zone, sock);
+ fptr = *ptr;
+ *ptr = (*ptr)->next;
+ free(fptr);
+ d->nelems--;
+ }
+ else ptr = &(*ptr)->next;
+ }
+ }
+ pthread_mutex_unlock(&d->tablelock);
+ mDNSPlatformTCPCloseConnection( sock );
+ }
+
+//
+// main update request handling
+//
+
+// Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
+mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
+ {
+ RRTableElem **rptr, *tmp;
+ int i, allocsize, bucket;
+ LargeCacheRecord lcr;
+ ResourceRecord *rr = &lcr.r.resrec;
+ const mDNSu8 *ptr, *end;
+ struct timeval time;
+ DNSQuestion zone;
+ char buf[MaxMsg];
+
+ if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
+ HdrNToH(pkt);
+ ptr = pkt->msg.data;
+ end = (mDNSu8 *)&pkt->msg + pkt->len;
+ ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone);
+ if (!ptr) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup; }
+ ptr = LocateAuthorities(&pkt->msg, end);
+ if (!ptr) { Log("UpdateLeaseTable: Format error"); goto cleanup; }
+
+ for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++)
+ {
+ mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse;
+
+ ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+ if (!ptr) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup; }
+ bucket = rr->namehash % d->nbuckets;
+ rptr = &d->table[bucket];
+
+ // handle deletions
+ if (rr->rrtype == kDNSQType_ANY && !rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
+ DeleteAllRRSets = mDNStrue; // delete all rrsets for a name
+ else if (!rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
+ DeleteOneRRSet = mDNStrue;
+ else if (!rr->rroriginalttl && rr->rrclass == kDNSClass_NONE)
+ DeleteOneRR = mDNStrue;
+
+ if (DeleteAllRRSets || DeleteOneRRSet || DeleteOneRR)
+ {
+ while (*rptr)
+ {
+ if (SameDomainName((*rptr)->rr.resrec.name, rr->name) &&
+ (DeleteAllRRSets ||
+ (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) ||
+ (DeleteOneRR && SameResourceRecord(&(*rptr)->rr.resrec, rr))))
+ {
+ tmp = *rptr;
+ VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf));
+ *rptr = (*rptr)->next;
+ free(tmp);
+ d->nelems--;
+ }
+ else rptr = &(*rptr)->next;
+ }
+ }
+ else if (lease > 0)
+ {
+ // see if add or refresh
+ while (*rptr && !SameResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
+ if (*rptr)
+ {
+ // refresh
+ if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
+ (*rptr)->expire = time.tv_sec + (unsigned)lease;
+ VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
+ }
+ else
+ {
+ // New record - add to table
+ if (d->nelems > d->nbuckets)
+ {
+ RehashTable(d);
+ bucket = rr->namehash % d->nbuckets;
+ rptr = &d->table[bucket];
+ }
+ if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
+ allocsize = sizeof(RRTableElem);
+ if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize);
+ tmp = malloc(allocsize);
+ if (!tmp) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; }
+ memcpy(&tmp->rr, &lcr.r, sizeof(CacheRecord) + rr->rdlength - InlineCacheRDSize);
+ tmp->rr.resrec.rdata = (RData *)&tmp->rr.rdatastorage;
+ AssignDomainName(&tmp->name, rr->name);
+ tmp->rr.resrec.name = &tmp->name;
+ tmp->expire = time.tv_sec + (unsigned)lease;
+ tmp->cli.sin_addr = pkt->src.sin_addr;
+ AssignDomainName(&tmp->zone, &zone.qname);
+ tmp->next = d->table[bucket];
+ d->table[bucket] = tmp;
+ d->nelems++;
+ VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
+ }
+ }
+ }
+
+ cleanup:
+ pthread_mutex_unlock(&d->tablelock);
+ HdrHToN(pkt);
+ }
+
+// Given a successful reply from a server, create a new reply that contains lease information
+// Replies are currently not signed !!!KRS change this
+mDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease)
+ {
+ PktMsg *reply;
+ mDNSu8 *ptr, *end;
+ mDNSOpaque16 flags;
+
+ (void)d; //unused
+ reply = malloc(sizeof(*reply));
+ if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; }
+ flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
+ flags.b[1] = 0;
+
+ InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags);
+ reply->src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // unused except for log messages
+ reply->src.sin_family = AF_INET;
+ ptr = reply->msg.data;
+ end = (mDNSu8 *)&reply->msg + sizeof(DNSMessage);
+ ptr = putUpdateLease(&reply->msg, ptr, lease);
+ if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; }
+ reply->len = ptr - (mDNSu8 *)&reply->msg;
+ return reply;
+ }
+
+
+// pkt is thread-local, not requiring locking
+
+mDNSlocal PktMsg*
+HandleRequest
+ (
+ DaemonInfo * self,
+ PktMsg * request
+ )
+ {
+ PktMsg * reply = NULL;
+ PktMsg * leaseReply;
+ PktMsg buf;
+ char addrbuf[32];
+ TCPSocket * sock = NULL;
+ mStatus err;
+ mDNSs32 lease = 0;
+ if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) == kDNSFlag0_OP_Update)
+ {
+ int i, adds = 0, dels = 0;
+ const mDNSu8 *ptr, *end = (mDNSu8 *)&request->msg + request->len;
+ HdrNToH(request);
+ lease = GetPktLease(NULL, &request->msg, end);
+ ptr = LocateAuthorities(&request->msg, end);
+ for (i = 0; i < request->msg.h.mDNS_numUpdates; i++)
+ {
+ LargeCacheRecord lcr;
+ ptr = GetLargeResourceRecord(NULL, &request->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+ if (lcr.r.resrec.rroriginalttl) adds++; else dels++;
+ }
+ HdrHToN(request);
+ if (adds && !lease)
+ {
+ static const mDNSOpaque16 UpdateRefused = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, kDNSFlag1_RC_Refused } };
+ Log("Rejecting Update Request with %d additions but no lease", adds);
+ reply = malloc(sizeof(*reply));
+ bzero(&reply->src, sizeof(reply->src));
+ reply->len = sizeof(DNSMessageHeader);
+ reply->zone = NULL;
+ reply->isZonePublic = 0;
+ InitializeDNSMessage(&reply->msg.h, request->msg.h.id, UpdateRefused);
+ return(reply);
+ }
+ if (lease > 1200) // Don't allow lease greater than 20 minutes
+ lease = 1200;
+ }
+ // Send msg to server, read reply
+
+ if ( request->len <= 512 )
+ {
+ mDNSBool trunc;
+
+ if ( UDPServerTransaction( self, request, &buf, &trunc) < 0 )
+ {
+ Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
+ }
+ else if ( trunc )
+ {
+ VLog("HandleRequest - answer truncated. Using TCP");
+ }
+ else
+ {
+ reply = &buf; // success
+ }
+ }
+
+ if ( !reply )
+ {
+ mDNSBool closed;
+ int res;
+
+ sock = ConnectToServer( self );
+ require_action_quiet( sock, exit, err = mStatus_UnknownErr ; Log( "Discarding request from %s due to connection errors", inet_ntop( AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
+
+ res = SendPacket( sock, request );
+ require_action_quiet( res >= 0, exit, err = mStatus_UnknownErr ; Log( "Couldn't relay message from %s to server. Discarding.", inet_ntop(AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
+
+ reply = RecvPacket( sock, &buf, &closed );
+ }
+
+ // IMPORTANT: reply is in network byte order at this point in the code
+ // We keep it this way because we send it back to the client in the same form
+
+ // Is it an update?
+
+ if ( reply && ( ( reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( kDNSFlag0_OP_Update | kDNSFlag0_QR_Response ) ) )
+ {
+ char pingmsg[4];
+ mDNSBool ok = SuccessfulUpdateTransaction( request, reply );
+ require_action( ok, exit, err = mStatus_UnknownErr; VLog( "Message from %s not a successful update.", inet_ntop(AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
+
+ UpdateLeaseTable( request, self, lease );
+
+ if ( lease > 0 )
+ {
+ leaseReply = FormatLeaseReply( self, reply, lease );
+
+ if ( !leaseReply )
+ {
+ Log("HandleRequest - unable to format lease reply");
+ }
+
+ // %%% Looks like a potential memory leak -- who frees the original reply?
+ reply = leaseReply;
+ }
+
+ // tell the main thread there was an update so it can send LLQs
+
+ if ( send( self->LLQEventNotifySock, pingmsg, sizeof( pingmsg ), 0 ) != sizeof( pingmsg ) )
+ {
+ LogErr("HandleRequest", "send");
+ }
+ }
+
+exit:
+
+ if ( sock )
+ {
+ mDNSPlatformTCPCloseConnection( sock );
+ }
+
+ if ( reply == &buf )
+ {
+ reply = malloc( sizeof( *reply ) );
+
+ if ( reply )
+ {
+ reply->len = buf.len;
+ memcpy(&reply->msg, &buf.msg, buf.len);
+ }
+ else
+ {
+ LogErr("HandleRequest", "malloc");
+ }
+ }
+
+ return reply;
+ }
+
+
+//
+// LLQ Support Routines
+//
+
+// Set fields of an LLQ OPT Resource Record
+mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, const mDNSOpaque64 *const id, mDNSs32 lease)
+ {
+ bzero(opt, sizeof(*opt));
+ mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+ opt->resrec.rrclass = NormalMaxDNSMessageData;
+ opt->resrec.rdlength = LLQ_OPT_RDLEN;
+ opt->resrec.rdestimate = LLQ_OPT_RDLEN;
+ opt->resrec.rdata->u.opt.opt = kDNSOpt_LLQ;
+ opt->resrec.rdata->u.opt.optlen = sizeof(LLQOptData);
+ opt->resrec.rdata->u.opt.OptData.llq.vers = kLLQ_Vers;
+ opt->resrec.rdata->u.opt.OptData.llq.llqOp = opcode;
+ opt->resrec.rdata->u.opt.OptData.llq.err = LLQErr_NoError;
+ opt->resrec.rdata->u.opt.OptData.llq.id = *id;
+ opt->resrec.rdata->u.opt.OptData.llq.llqlease = lease;
+ }
+
+// Calculate effective remaining lease of an LLQ
+mDNSlocal mDNSu32 LLQLease(LLQEntry *e)
+ {
+ struct timeval t;
+
+ gettimeofday(&t, NULL);
+ if (e->expire < t.tv_sec) return 0;
+ else return e->expire - t.tv_sec;
+ }
+
+mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
+ {
+ int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
+ LLQEntry **ptr = &d->LLQTable[bucket];
+ AnswerListElem *a = e->AnswerList;
+ char addr[32];
+
+ inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+ VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
+
+ if (a && !(--a->refcount) && d->AnswerTableCount >= LLQ_TABLESIZE)
+ {
+ // currently, generating initial answers blocks the main thread, so we keep the answer list
+ // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
+ // if the ref count drops to zero AND there are more table elements than buckets
+ // !!!KRS update this when we make the table dynamically growable
+
+ CacheRecord *cr = a->KnownAnswers, *tmp;
+ AnswerListElem **tbl = &d->AnswerTable[bucket];
+
+ while (cr)
+ {
+ tmp = cr;
+ cr = cr->next;
+ free(tmp);
+ }
+
+ while (*tbl && *tbl != a) tbl = &(*tbl)->next;
+ if (*tbl) { *tbl = (*tbl)->next; free(a); d->AnswerTableCount--; }
+ else Log("Error: DeleteLLQ - AnswerList not found in table");
+ }
+
+ // remove LLQ from table, free memory
+ while(*ptr && *ptr != e) ptr = &(*ptr)->next;
+ if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
+ *ptr = (*ptr)->next;
+ free(e);
+ }
+
+mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst, TCPSocket *sock)
+ {
+ char addr[32];
+ int err = -1;
+
+ HdrHToN(pkt);
+
+ if ( sock )
+ {
+ if ( SendPacket( sock, pkt ) != 0 )
+ {
+ LogErr("DaemonInfo", "MySend");
+ Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
+ }
+ }
+ else
+ {
+ if (sendto(d->llq_udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
+ {
+ LogErr("DaemonInfo", "sendto");
+ Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
+ }
+ }
+
+ err = 0;
+ HdrNToH(pkt);
+ return err;
+ }
+
+mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e)
+ {
+ PktMsg q;
+ int i;
+ TCPSocket *sock = NULL;
+ const mDNSu8 *ansptr;
+ mDNSu8 *end = q.msg.data;
+ PktMsg buf, *reply = NULL;
+ LargeCacheRecord lcr;
+ CacheRecord *AnswerList = NULL;
+ mDNSu8 rcode;
+
+ VLog("Querying server for %##s type %d", e->name.c, e->type);
+
+ InitializeDNSMessage(&q.msg.h, zeroID, uQueryFlags);
+
+ end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN);
+ if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
+ q.len = (int)(end - (mDNSu8 *)&q.msg);
+
+ HdrHToN(&q);
+
+ if (!e->UseTCP)
+ {
+ mDNSBool trunc;
+
+ if (UDPServerTransaction(d, &q, &buf, &trunc) < 0)
+ Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e->name.c);
+ else if (trunc)
+ { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e->name.c); e->UseTCP = mDNStrue; }
+ else reply = &buf; // success
+ }
+
+ if (!reply)
+ {
+ mDNSBool closed;
+
+ sock = ConnectToServer(d);
+ if (!sock) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
+ if (SendPacket( sock, &q)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock ); goto end; }
+ reply = RecvPacket( sock, NULL, &closed );
+ mDNSPlatformTCPCloseConnection( sock );
+ require_action( reply, end, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
+ }
+
+ HdrNToH(&q);
+ if (reply) HdrNToH(reply);
+
+ if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
+ { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
+ rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
+ if (rcode && rcode != kDNSFlag1_RC_NXDomain) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e->name.c, e->type, rcode); goto end; }
+
+ end = (mDNSu8 *)&reply->msg + reply->len;
+ ansptr = LocateAnswers(&reply->msg, end);
+ if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
+
+ for (i = 0; i < reply->msg.h.numAnswers; i++)
+ {
+ ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
+ if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
+ if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
+ {
+ Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
+ lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
+ }
+ else
+ {
+ CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
+ if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
+ cr->next = AnswerList;
+ AnswerList = cr;
+ }
+ }
+
+ end:
+ if (reply && reply != &buf) free(reply);
+ return AnswerList;
+ }
+
+// Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
+mDNSlocal void *UpdateAnswerList(void *args)
+ {
+ CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer"
+ DaemonInfo *d = ((UpdateAnswerListArgs *)args)->d;
+ AnswerListElem *a = ((UpdateAnswerListArgs *)args)->a;
+
+ free(args);
+ args = NULL;
+
+ // get up to date answers
+ NewAnswers = AnswerQuestion(d, a);
+
+ // first pass - mark all answers for deletion
+ for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
+ (*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete
+
+ // second pass - mark answers pre-existent
+ for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
+ {
+ for (na = &NewAnswers; *na; na = &(*na)->next)
+ {
+ if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec))
+ { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
+ }
+ }
+
+ // third pass - add new records to Event list
+ na = &NewAnswers;
+ while (*na)
+ {
+ for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
+ if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
+ if (!*ka)
+ {
+ // answer is not in list - splice from NewAnswers list, add to Event list
+ cr = *na;
+ *na = (*na)->next; // splice from list
+ cr->next = a->EventList; // add spliced record to event list
+ a->EventList = cr;
+ cr->resrec.rroriginalttl = 1; // 1 means add
+ }
+ else na = &(*na)->next;
+ }
+
+ // move all the removes from the answer list to the event list
+ ka = &a->KnownAnswers;
+ while (*ka)
+ {
+ if ((*ka)->resrec.rroriginalttl == (unsigned)-1)
+ {
+ cr = *ka;
+ *ka = (*ka)->next;
+ cr->next = a->EventList;
+ a->EventList = cr;
+ }
+ else ka = &(*ka)->next;
+ }
+
+ // lastly, free the remaining records (known answers) in NewAnswers list
+ while (NewAnswers)
+ {
+ cr = NewAnswers;
+ NewAnswers = NewAnswers->next;
+ free(cr);
+ }
+
+ return NULL;
+ }
+
+mDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e)
+ {
+ PktMsg response;
+ CacheRecord *cr;
+ mDNSu8 *end = (mDNSu8 *)&response.msg.data;
+ mDNSOpaque16 msgID;
+ char rrbuf[MaxMsg], addrbuf[32];
+ AuthRecord opt;
+
+ // Should this really be random? Do we use the msgID on the receiving end?
+ msgID.NotAnInteger = random();
+ if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
+ InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
+ end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+ if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
+
+ // put adds/removes in packet
+ for (cr = e->AnswerList->EventList; cr; cr = cr->next)
+ {
+ if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf);
+ VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove": "Add", rrbuf);
+ end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl);
+ if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
+ }
+
+ FormatLLQOpt(&opt, kLLQOp_Event, &e->id, LLQLease(e));
+ end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
+ if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
+
+ response.len = (int)(end - (mDNSu8 *)&response.msg);
+ if (SendLLQ(d, &response, e->cli, NULL ) < 0) LogMsg("Error: SendEvents - SendLLQ");
+ }
+
+mDNSlocal void PrintLLQAnswers(DaemonInfo *d)
+ {
+ int i;
+ char rrbuf[MaxMsg];
+
+ Log("Printing LLQ Answer Table contents");
+
+ for (i = 0; i < LLQ_TABLESIZE; i++)
+ {
+ AnswerListElem *a = d->AnswerTable[i];
+ while(a)
+ {
+ int ancount = 0;
+ const CacheRecord *rr = a->KnownAnswers;
+ while (rr) { ancount++; rr = rr->next; }
+ Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a, a->name.c, a->type, a->refcount, ancount);
+ for (rr = a->KnownAnswers; rr; rr = rr->next) Log("\t%s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, rrbuf));
+ a = a->next;
+ }
+ }
+ }
+
+mDNSlocal void PrintLLQTable(DaemonInfo *d)
+ {
+ LLQEntry *e;
+ char addr[32];
+ int i;
+
+ Log("Printing LLQ table contents");
+
+ for (i = 0; i < LLQ_TABLESIZE; i++)
+ {
+ e = d->LLQTable[i];
+ while(e)
+ {
+ char *state;
+
+ switch (e->state)
+ {
+ case RequestReceived: state = "RequestReceived"; break;
+ case ChallengeSent: state = "ChallengeSent"; break;
+ case Established: state = "Established"; break;
+ default: state = "unknown";
+ }
+ inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+
+ Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
+ addr, state, e->qname.c, e->qtype, e->lease, LLQLease(e), e->AnswerList);
+ e = e->next;
+ }
+ }
+ }
+
+// Send events to clients as a result of a change in the zone
+mDNSlocal void GenLLQEvents(DaemonInfo *d)
+ {
+ LLQEntry **e;
+ int i;
+ struct timeval t;
+ UpdateAnswerListArgs *args;
+
+ VLog("Generating LLQ Events");
+
+ gettimeofday(&t, NULL);
+
+ // get all answers up to date
+ for (i = 0; i < LLQ_TABLESIZE; i++)
+ {
+ AnswerListElem *a = d->AnswerTable[i];
+ while(a)
+ {
+ args = malloc(sizeof(*args));
+ if (!args) { LogErr("GenLLQEvents", "malloc"); return; }
+ args->d = d;
+ args->a = a;
+ if (pthread_create(&a->tid, NULL, UpdateAnswerList, args) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
+ usleep(1);
+ a = a->next;
+ }
+ }
+
+ for (i = 0; i < LLQ_TABLESIZE; i++)
+ {
+ AnswerListElem *a = d->AnswerTable[i];
+ while(a)
+ {
+ if (pthread_join(a->tid, NULL)) LogErr("GenLLQEvents", "pthread_join");
+ a = a->next;
+ }
+ }
+
+ // for each established LLQ, send events
+ for (i = 0; i < LLQ_TABLESIZE; i++)
+ {
+ e = &d->LLQTable[i];
+ while(*e)
+ {
+ if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e);
+ else
+ {
+ if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e);
+ e = &(*e)->next;
+ }
+ }
+ }
+
+ // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
+ for (i = 0; i < LLQ_TABLESIZE; i++)
+ {
+ AnswerListElem *a = d->AnswerTable[i];
+ while(a)
+ {
+ if (a->EventList)
+ {
+ CacheRecord *cr = a->EventList, *tmp;
+ while (cr)
+ {
+ tmp = cr;
+ cr = cr->next;
+ if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp);
+ else
+ {
+ tmp->next = a->KnownAnswers;
+ a->KnownAnswers = tmp;
+ tmp->resrec.rroriginalttl = 0;
+ }
+ }
+ a->EventList = NULL;
+ }
+ a = a->next;
+ }
+ }
+ }
+
+mDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e)
+ {
+ int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
+ AnswerListElem *a = d->AnswerTable[bucket];
+ while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next;
+ if (!a)
+ {
+ a = malloc(sizeof(*a));
+ if (!a) { LogErr("SetAnswerList", "malloc"); return; }
+ AssignDomainName(&a->name, &e->qname);
+ a->type = e->qtype;
+ a->refcount = 0;
+ a->EventList = NULL;
+ a->UseTCP = mDNSfalse;
+ a->next = d->AnswerTable[bucket];
+ d->AnswerTable[bucket] = a;
+ d->AnswerTableCount++;
+ a->KnownAnswers = AnswerQuestion(d, a);
+ }
+
+ e->AnswerList = a;
+ a->refcount ++;
+ }
+
+ // Allocate LLQ entry, insert into table
+mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease )
+ {
+ char addr[32];
+ struct timeval t;
+ int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
+ LLQEntry *e;
+
+ e = malloc(sizeof(*e));
+ if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
+
+ inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
+ VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
+
+ // initialize structure
+ e->cli = cli;
+ AssignDomainName(&e->qname, qname);
+ e->qtype = qtype;
+ e->id = zeroOpaque64;
+ e->state = RequestReceived;
+ e->AnswerList = NULL;
+
+ if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
+ else if (lease > LLQ_MAX_LEASE) lease = LLQ_MAX_LEASE;
+
+ gettimeofday(&t, NULL);
+ e->expire = t.tv_sec + (int)lease;
+ e->lease = lease;
+
+ // add to table
+ e->next = d->LLQTable[bucket];
+ d->LLQTable[bucket] = e;
+
+ return e;
+ }
+
+// Handle a refresh request from client
+mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
+ {
+ AuthRecord opt;
+ PktMsg ack;
+ mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
+ char addr[32];
+
+ inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+ VLog("%s LLQ for %##s from %s", llq->llqlease ? "Refreshing" : "Deleting", e->qname.c, addr);
+
+ if (llq->llqlease)
+ {
+ struct timeval t;
+ if (llq->llqlease < LLQ_MIN_LEASE) llq->llqlease = LLQ_MIN_LEASE;
+ else if (llq->llqlease > LLQ_MAX_LEASE) llq->llqlease = LLQ_MIN_LEASE;
+ gettimeofday(&t, NULL);
+ e->expire = t.tv_sec + llq->llqlease;
+ }
+
+ ack.src.sin_addr.s_addr = 0; // unused
+ InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
+ end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+ if (!end) { Log("Error: putQuestion"); return; }
+
+ FormatLLQOpt(&opt, kLLQOp_Refresh, &e->id, llq->llqlease ? LLQLease(e) : 0);
+ end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
+ if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+
+ ack.len = (int)(end - (mDNSu8 *)&ack.msg);
+ if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQRefresh");
+
+ if (llq->llqlease) e->state = Established;
+ else DeleteLLQ(d, e);
+ }
+
+// Complete handshake with Ack an initial answers
+mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock)
+ {
+ char addr[32];
+ CacheRecord *ptr;
+ AuthRecord opt;
+ PktMsg ack;
+ mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
+ char rrbuf[MaxMsg], addrbuf[32];
+
+ inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
+
+ if (!mDNSSameOpaque64(&llq->id, &e->id) ||
+ llq->vers != kLLQ_Vers ||
+ llq->llqOp != kLLQOp_Setup ||
+ llq->err != LLQErr_NoError ||
+ llq->llqlease > e->lease + LLQ_LEASE_FUDGE ||
+ llq->llqlease < e->lease - LLQ_LEASE_FUDGE)
+ {
+ Log("Incorrect challenge response from %s", addr);
+ return;
+ }
+
+ if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
+ else VLog("Delivering LLQ ack + answers for %##s", e->qname.c);
+
+ // format ack + answers
+ ack.src.sin_addr.s_addr = 0; // unused
+ InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
+ end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+ if (!end) { Log("Error: putQuestion"); return; }
+
+ if (e->state != Established) { SetAnswerList(d, e); e->state = Established; }
+
+ if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
+ for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next)
+ {
+ if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
+ VLog("%s Intitial Answer - %s", addr, rrbuf);
+ end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
+ if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+ }
+
+ FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
+ end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
+ if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+
+ ack.len = (int)(end - (mDNSu8 *)&ack.msg);
+ if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQCompleteHandshake");
+ }
+
+mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
+ {
+ struct timeval t;
+ PktMsg challenge;
+ mDNSu8 *end = challenge.msg.data;
+ AuthRecord opt;
+
+ if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
+ else VLog("Sending LLQ setup challenge for %##s", e->qname.c);
+
+ if (!mDNSOpaque64IsZero(&llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
+ if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
+
+ if (mDNSOpaque64IsZero(&e->id)) // don't regenerate random ID for retransmissions
+ {
+ // construct ID <time><random>
+ gettimeofday(&t, NULL);
+ e->id.l[0] = t.tv_sec;
+ e->id.l[1] = random();
+ }
+
+ // format response (query + LLQ opt rr)
+ challenge.src.sin_addr.s_addr = 0; // unused
+ InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
+ end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
+ if (!end) { Log("Error: putQuestion"); return; }
+ FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
+ end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
+ if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
+ challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
+ if (SendLLQ(d, &challenge, e->cli, NULL)) { Log("Error: LLQSetupChallenge"); return; }
+ e->state = ChallengeSent;
+ }
+
+// Take action on an LLQ message from client. Entry must be initialized and in table
+mDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
+ {
+ switch(e->state)
+ {
+ case RequestReceived:
+ if ( sock )
+ {
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ e->id.l[0] = t.tv_sec; // construct ID <time><random>
+ e->id.l[1] = random();
+ llq->id = e->id;
+ LLQCompleteHandshake( d, e, llq, msgID, sock );
+
+ // Set the state to established because we've just set the LLQ up using TCP
+ e->state = Established;
+ }
+ else
+ {
+ LLQSetupChallenge(d, e, llq, msgID);
+ }
+ return;
+ case ChallengeSent:
+ if (mDNSOpaque64IsZero(&llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
+ else LLQCompleteHandshake(d, e, llq, msgID, sock );
+ return;
+ case Established:
+ if (mDNSOpaque64IsZero(&llq->id))
+ {
+ // client started over. reset state.
+ LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->llqlease );
+ if (!newe) return;
+ DeleteLLQ(d, e);
+ LLQSetupChallenge(d, newe, llq, msgID);
+ return;
+ }
+ else if (llq->llqOp == kLLQOp_Setup)
+ { LLQCompleteHandshake(d, e, llq, msgID, sock); return; } // Ack lost
+ else if (llq->llqOp == kLLQOp_Refresh)
+ { LLQRefresh(d, e, llq, msgID, sock); return; }
+ else { Log("Unhandled message for established LLQ"); return; }
+ }
+ }
+
+mDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, const mDNSOpaque64 *const id)
+ {
+ int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
+ LLQEntry *ptr = d->LLQTable[bucket];
+
+ while(ptr)
+ {
+ if (((ptr->state == ChallengeSent && mDNSOpaque64IsZero(id) && (cli.sin_port == ptr->cli.sin_port)) || // zero-id due to packet loss OK in state ChallengeSent
+ mDNSSameOpaque64(id, &ptr->id)) && // id match
+ (cli.sin_addr.s_addr == ptr->cli.sin_addr.s_addr) && (qtype == ptr->qtype) && SameDomainName(&ptr->qname, qname)) // same source, type, qname
+ return ptr;
+ ptr = ptr->next;
+ }
+ return NULL;
+ }
+
+mDNSlocal int
+RecvNotify
+ (
+ DaemonInfo * d,
+ PktMsg * pkt
+ )
+ {
+ int res;
+ int err = 0;
+
+ pkt->msg.h.flags.b[0] |= kDNSFlag0_QR_Response;
+
+ res = sendto( d->udpsd, &pkt->msg, pkt->len, 0, ( struct sockaddr* ) &pkt->src, sizeof( pkt->src ) );
+ require_action( res == ( int ) pkt->len, exit, err = mStatus_UnknownErr; LogErr( "RecvNotify", "sendto" ) );
+
+exit:
+
+ return err;
+ }
+
+
+mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
+ {
+ DNSQuestion q;
+ LargeCacheRecord opt;
+ int i, err = -1;
+ char addr[32];
+ const mDNSu8 *qptr = pkt->msg.data;
+ const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
+ const mDNSu8 *aptr;
+ LLQOptData *llq = NULL;
+ LLQEntry *e = NULL;
+
+ HdrNToH(pkt);
+ aptr = LocateAdditionals(&pkt->msg, end); // Can't do this until after HdrNToH(pkt);
+ inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
+
+ VLog("Received LLQ msg from %s", addr);
+ // sanity-check packet
+ if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
+ {
+ Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);
+ goto end;
+ }
+
+ // Locate the OPT record.
+ // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
+ // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
+ // but not necessarily the *last* entry in the Additional Section.
+ for (i = 0; i < pkt->msg.h.numAdditionals; i++)
+ {
+ aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
+ if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
+ if (opt.r.resrec.rrtype == kDNSType_OPT) break;
+ }
+
+ // validate OPT
+ if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr); goto end; }
+ if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * LLQ_OPT_RDLEN) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); }
+
+ // dispatch each question
+ for (i = 0; i < pkt->msg.h.numQuestions; i++)
+ {
+ qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
+ if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; }
+ llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt.OptData.llq + i; // point into OptData at index i
+ if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
+
+ e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, &llq->id);
+ if (!e)
+ {
+ // no entry - if zero ID, create new
+ e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->llqlease );
+ if (!e) goto end;
+ }
+ UpdateLLQ(d, e, llq, pkt->msg.h.id, sock);
+ }
+ err = 0;
+
+ end:
+ HdrHToN(pkt);
+ return err;
+ }
+
+
+mDNSlocal mDNSBool IsAuthorized( DaemonInfo * d, PktMsg * pkt, DomainAuthInfo ** key, mDNSu16 * rcode, mDNSu16 * tcode )
+ {
+ const mDNSu8 * lastPtr = NULL;
+ const mDNSu8 * ptr = NULL;
+ DomainAuthInfo * keys;
+ mDNSu8 * end = ( mDNSu8* ) &pkt->msg + pkt->len;
+ LargeCacheRecord lcr;
+ mDNSBool hasTSIG = mDNSfalse;
+ mDNSBool strip = mDNSfalse;
+ mDNSBool ok = mDNSfalse;
+ int i;
+
+ // Unused parameters
+
+ ( void ) d;
+
+ HdrNToH(pkt);
+
+ *key = NULL;
+
+ if ( pkt->msg.h.numAdditionals )
+ {
+ ptr = LocateAdditionals(&pkt->msg, end);
+ if (ptr)
+ {
+ for (i = 0; i < pkt->msg.h.numAdditionals; i++)
+ {
+ lastPtr = ptr;
+ ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
+ if (!ptr)
+ {
+ Log("Unable to read additional record");
+ lastPtr = NULL;
+ break;
+ }
+ }
+
+ hasTSIG = ( ptr && lcr.r.resrec.rrtype == kDNSType_TSIG );
+ }
+ else
+ {
+ LogMsg( "IsAuthorized: unable to find Additional section" );
+ }
+ }
+
+ // If we don't know what zone this is, then it's authorized.
+
+ if ( !pkt->zone )
+ {
+ ok = mDNStrue;
+ strip = mDNSfalse;
+ goto exit;
+ }
+
+ if ( IsQuery( pkt ) )
+ {
+ keys = pkt->zone->queryKeys;
+ strip = mDNStrue;
+ }
+ else if ( IsUpdate( pkt ) )
+ {
+ keys = pkt->zone->updateKeys;
+ strip = mDNSfalse;
+ }
+ else
+ {
+ ok = mDNStrue;
+ strip = mDNSfalse;
+ goto exit;
+ }
+
+ if ( pkt->isZonePublic )
+ {
+ ok = mDNStrue;
+ goto exit;
+ }
+
+ // If there are no keys, then we're authorized
+
+ if ( ( hasTSIG && !keys ) || ( !hasTSIG && keys ) )
+ {
+ Log( "Invalid TSIG spec %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadKey;
+ strip = mDNStrue;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ // Find the right key
+
+ for ( *key = keys; *key; *key = (*key)->next )
+ {
+ if ( SameDomainName( lcr.r.resrec.name, &(*key)->keyname ) )
+ {
+ break;
+ }
+ }
+
+ if ( !(*key) )
+ {
+ Log( "Invalid TSIG name %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
+ *rcode = kDNSFlag1_RC_NotAuth;
+ *tcode = TSIG_ErrBadKey;
+ strip = mDNStrue;
+ ok = mDNSfalse;
+ goto exit;
+ }
+
+ // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
+ // lifting of message verification
+
+ pkt->msg.h.numAdditionals--;
+
+ HdrHToN( pkt );
+
+ ok = DNSDigest_VerifyMessage( &pkt->msg, ( mDNSu8* ) lastPtr, &lcr, (*key), rcode, tcode );
+
+ HdrNToH( pkt );
+
+ pkt->msg.h.numAdditionals++;
+
+exit:
+
+ if ( hasTSIG && strip )
+ {
+ // Strip the TSIG from the message
+
+ pkt->msg.h.numAdditionals--;
+ pkt->len = lastPtr - ( mDNSu8* ) ( &pkt->msg );
+ }
+
+ HdrHToN(pkt);
+
+ return ok;
+ }
+
+// request handler wrappers for TCP and UDP requests
+// (read message off socket, fork thread that invokes main processing routine and handles cleanup)
+
+mDNSlocal void*
+UDPMessageHandler
+ (
+ void * vptr
+ )
+ {
+ UDPContext * context = ( UDPContext* ) vptr;
+ PktMsg * reply = NULL;
+ int res;
+ mStatus err;
+
+ // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
+ // may give us a long answer that would require truncation for UDP delivery to client
+
+ reply = HandleRequest( context->d, &context->pkt );
+ require_action( reply, exit, err = mStatus_UnknownErr );
+
+ res = sendto( context->sd, &reply->msg, reply->len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
+ require_action_quiet( res == ( int ) reply->len, exit, LogErr( "UDPMessageHandler", "sendto" ) );
+
+exit:
+
+ if ( reply )
+ {
+ free( reply );
+ }
+
+ free( context );
+
+ pthread_exit( NULL );
+
+ return NULL;
+ }
+
+
+mDNSlocal int
+RecvUDPMessage
+ (
+ DaemonInfo * self,
+ int sd
+ )
+ {
+ UDPContext * context = NULL;
+ pthread_t tid;
+ mDNSu16 rcode;
+ mDNSu16 tcode;
+ DomainAuthInfo * key;
+ unsigned int clisize = sizeof( context->cliaddr );
+ int res;
+ mStatus err = mStatus_NoError;
+
+ context = malloc( sizeof( UDPContext ) );
+ require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) );
+
+ bzero( context, sizeof( *context ) );
+ context->d = self;
+ context->sd = sd;
+
+ res = recvfrom(sd, &context->pkt.msg, sizeof(context->pkt.msg), 0, (struct sockaddr *)&context->cliaddr, &clisize);
+
+ require_action( res >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvUDPMessage", "recvfrom" ) );
+ context->pkt.len = res;
+ require_action( clisize == sizeof( context->cliaddr ), exit, err = mStatus_UnknownErr ; Log( "Client address of unknown size %d", clisize ) );
+ context->pkt.src = context->cliaddr;
+
+ // Set the zone in the packet
+
+ SetZone( context->d, &context->pkt );
+
+ // Notify messages handled by main thread
+
+ if ( IsNotify( &context->pkt ) )
+ {
+ int err = RecvNotify( self, &context->pkt );
+ free(context);
+ return err;
+ }
+ else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
+ {
+ if ( IsLLQRequest( &context->pkt ) )
+ {
+ // LLQ messages handled by main thread
+
+ int err = RecvLLQ( self, &context->pkt, NULL );
+ free(context);
+ return err;
+ }
+
+ if ( IsLLQAck(&context->pkt ) )
+ {
+ // !!!KRS need to do acks + retrans
+
+ free(context);
+ return 0;
+ }
+
+ err = pthread_create( &tid, NULL, UDPMessageHandler, context );
+ require_action( !err, exit, LogErr( "RecvUDPMessage", "pthread_create" ) );
+
+ pthread_detach(tid);
+ }
+ else
+ {
+ PktMsg reply;
+ int res;
+
+ memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
+
+ reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
+ reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_NXDomain;
+
+ res = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
+ require_action_quiet( res == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
+
+ err = mStatus_NoAuth;
+ }
+
+exit:
+
+ if ( err && context )
+ {
+ free( context );
+ }
+
+ return err;
+ }
+
+
+mDNSlocal void
+FreeTCPContext
+ (
+ TCPContext * context
+ )
+ {
+ if ( context )
+ {
+ if ( context->sock )
+ {
+ mDNSPlatformTCPCloseConnection( context->sock );
+ }
+
+ free( context );
+ }
+ }
+
+
+mDNSlocal void*
+TCPMessageHandler
+ (
+ void * vptr
+ )
+ {
+ TCPContext * context = ( TCPContext* ) vptr;
+ PktMsg * reply = NULL;
+ int res;
+ char buf[32];
+
+ //!!!KRS if this read blocks indefinitely, we can run out of threads
+ // read the request
+
+ reply = HandleRequest( context->d, &context->pkt );
+ require_action_quiet( reply, exit, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
+
+ // deliver reply to client
+
+ res = SendPacket( context->sock, reply );
+ require_action( res >= 0, exit, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
+
+exit:
+
+ FreeTCPContext( context );
+
+ if ( reply )
+ {
+ free( reply );
+ }
+
+ pthread_exit(NULL);
+ }
+
+
+mDNSlocal void
+RecvTCPMessage
+ (
+ void * param
+ )
+ {
+ TCPContext * context = ( TCPContext* ) param;
+ mDNSu16 rcode;
+ mDNSu16 tcode;
+ pthread_t tid;
+ DomainAuthInfo * key;
+ PktMsg * pkt;
+ mDNSBool closed;
+ mDNSBool freeContext = mDNStrue;
+ mStatus err = mStatus_NoError;
+
+ // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
+ // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
+ // wire. We'll let it do that, and wait for the next packet which will be ours.
+
+ pkt = RecvPacket( context->sock, &context->pkt, &closed );
+ if (pkt) HdrNToH(pkt);
+ require_action( pkt || !closed, exit, err = mStatus_UnknownErr; LogMsg( "client disconnected" ) );
+
+ if ( pkt )
+ {
+ // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
+ // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
+ // are sent over UDP
+
+ RemoveSourceFromEventLoop( context->d, context->sock );
+
+ // Set's the DNS Zone that is associated with this message
+
+ SetZone( context->d, &context->pkt );
+
+ // IsAuthorized will make sure the message is authorized for the designated zone.
+ // After verifying the signature, it will strip the TSIG from the message
+
+ if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
+ {
+ if ( IsLLQRequest( &context->pkt ) )
+ {
+ // LLQ messages handled by main thread
+ RecvLLQ( context->d, &context->pkt, context->sock);
+ }
+ else
+ {
+ err = pthread_create( &tid, NULL, TCPMessageHandler, context );
+
+ if ( err )
+ {
+ LogErr( "RecvTCPMessage", "pthread_create" );
+ err = mStatus_NoError;
+ goto exit;
+ }
+
+ // Let the thread free the context
+
+ freeContext = mDNSfalse;
+
+ pthread_detach(tid);
+ }
+ }
+ else
+ {
+ PktMsg reply;
+
+ LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context->pkt.src.sin_addr ), pkt->zone->name.c );
+
+ memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
+
+ reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
+ reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_Refused;
+
+ SendPacket( context->sock, &reply );
+ }
+ }
+ else
+ {
+ freeContext = mDNSfalse;
+ }
+
+exit:
+
+ if ( err )
+ {
+ RemoveSourceFromEventLoop( context->d, context->sock );
+ }
+
+ if ( freeContext )
+ {
+ FreeTCPContext( context );
+ }
+ }
+
+
+mDNSlocal int
+AcceptTCPConnection
+ (
+ DaemonInfo * self,
+ int sd,
+ TCPSocketFlags flags
+ )
+ {
+ TCPContext * context = NULL;
+ unsigned int clilen = sizeof( context->cliaddr);
+ int newSock;
+ mStatus err = mStatus_NoError;
+
+ context = ( TCPContext* ) malloc( sizeof( TCPContext ) );
+ require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) );
+ bzero( context, sizeof( sizeof( TCPContext ) ) );
+ context->d = self;
+ newSock = accept( sd, ( struct sockaddr* ) &context->cliaddr, &clilen );
+ require_action( newSock != -1, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "accept" ) );
+
+ context->sock = mDNSPlatformTCPAccept( flags, newSock );
+ require_action( context->sock, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
+
+ err = AddSourceToEventLoop( self, context->sock, RecvTCPMessage, context );
+ require_action( !err, exit, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
+
+exit:
+
+ if ( err && context )
+ {
+ free( context );
+ context = NULL;
+ }
+
+ return err;
+ }
+
+
+// main event loop
+// listen for incoming requests, periodically check table for expired records, respond to signals
+mDNSlocal int Run(DaemonInfo *d)
+ {
+ int staticMaxFD, nfds;
+ fd_set rset;
+ struct timeval timenow, timeout, EventTS, tablecheck = { 0, 0 };
+ mDNSBool EventsPending = mDNSfalse;
+
+ VLog("Listening for requests...");
+
+ staticMaxFD = 0;
+
+ if ( d->tcpsd + 1 > staticMaxFD ) staticMaxFD = d->tcpsd + 1;
+ if ( d->udpsd + 1 > staticMaxFD ) staticMaxFD = d->udpsd + 1;
+ if ( d->tlssd + 1 > staticMaxFD ) staticMaxFD = d->tlssd + 1;
+ if ( d->llq_tcpsd + 1 > staticMaxFD ) staticMaxFD = d->llq_tcpsd + 1;
+ if ( d->llq_udpsd + 1 > staticMaxFD ) staticMaxFD = d->llq_udpsd + 1;
+ if ( d->LLQEventListenSock + 1 > staticMaxFD ) staticMaxFD = d->LLQEventListenSock + 1;
+
+ while(1)
+ {
+ EventSource * source;
+ int maxFD;
+
+ // set timeout
+ timeout.tv_sec = timeout.tv_usec = 0;
+ if (gettimeofday(&timenow, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
+
+ if (EventsPending)
+ {
+ if (timenow.tv_sec - EventTS.tv_sec >= 5) // if we've been waiting 5 seconds for a "quiet" period to send
+ { GenLLQEvents(d); EventsPending = mDNSfalse; } // events, we go ahead and do it now
+ else timeout.tv_usec = 500000; // else do events after 1/2 second with no new events or LLQs
+ }
+ if (!EventsPending)
+ {
+ // if no pending events, timeout when we need to check for expired records
+ if (tablecheck.tv_sec && timenow.tv_sec - tablecheck.tv_sec >= 0)
+ { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; } // table check overdue
+ if (!tablecheck.tv_sec) tablecheck.tv_sec = timenow.tv_sec + EXPIRATION_INTERVAL;
+ timeout.tv_sec = tablecheck.tv_sec - timenow.tv_sec;
+ }
+
+ FD_ZERO(&rset);
+ FD_SET( d->tcpsd, &rset );
+ FD_SET( d->udpsd, &rset );
+ FD_SET( d->tlssd, &rset );
+ FD_SET( d->llq_tcpsd, &rset );
+ FD_SET( d->llq_udpsd, &rset );
+ FD_SET( d->LLQEventListenSock, &rset );
+
+ maxFD = staticMaxFD;
+
+ for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
+ {
+ FD_SET( source->fd, &rset );
+
+ if ( source->fd > maxFD )
+ {
+ maxFD = source->fd;
+ }
+ }
+
+ nfds = select( maxFD + 1, &rset, NULL, NULL, &timeout);
+ if (nfds < 0)
+ {
+ if (errno == EINTR)
+ {
+ if (terminate)
+ {
+ // close sockets to prevent clients from making new requests during shutdown
+ close( d->tcpsd );
+ close( d->udpsd );
+ close( d->tlssd );
+ close( d->llq_tcpsd );
+ close( d->llq_udpsd );
+ d->tcpsd = d->udpsd = d->tlssd = d->llq_tcpsd = d->llq_udpsd = -1;
+ DeleteRecords(d, mDNStrue);
+ return 0;
+ }
+ else if (dumptable)
+ {
+ Log( "Received SIGINFO" );
+
+ PrintLeaseTable(d);
+ PrintLLQTable(d);
+ PrintLLQAnswers(d);
+ dumptable = 0;
+ }
+ else if (hangup)
+ {
+ int err;
+
+ Log( "Received SIGHUP" );
+
+ err = ParseConfig( d, cfgfile );
+
+ if ( err )
+ {
+ LogErr( "Run", "ParseConfig" );
+ return -1;
+ }
+
+ hangup = 0;
+ }
+ else
+ {
+ Log("Received unhandled signal - continuing");
+ }
+ }
+ else
+ {
+ LogErr("Run", "select"); return -1;
+ }
+ }
+ else if (nfds)
+ {
+ if (FD_ISSET(d->udpsd, &rset)) RecvUDPMessage( d, d->udpsd );
+ if (FD_ISSET(d->llq_udpsd, &rset)) RecvUDPMessage( d, d->llq_udpsd );
+ if (FD_ISSET(d->tcpsd, &rset)) AcceptTCPConnection( d, d->tcpsd, 0 );
+ if (FD_ISSET(d->llq_tcpsd, &rset)) AcceptTCPConnection( d, d->llq_tcpsd, 0 );
+ if (FD_ISSET(d->tlssd, &rset)) AcceptTCPConnection( d, d->tlssd, TCP_SOCKET_FLAGS );
+ if (FD_ISSET(d->LLQEventListenSock, &rset))
+ {
+ // clear signalling data off socket
+ char buf[256];
+ recv(d->LLQEventListenSock, buf, 256, 0);
+ if (!EventsPending)
+ {
+ EventsPending = mDNStrue;
+ if (gettimeofday(&EventTS, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
+ }
+ }
+
+ for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
+ {
+ if ( FD_ISSET( source->fd, &rset ) )
+ {
+ source->callback( source->context );
+ break; // in case we removed this guy from the event loop
+ }
+ }
+ }
+ else
+ {
+ // timeout
+ if (EventsPending) { GenLLQEvents(d); EventsPending = mDNSfalse; }
+ else { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; }
+ }
+ }
+ return 0;
+ }
+
+// signal handler sets global variables, which are inspected by main event loop
+// (select automatically returns due to the handled signal)
+mDNSlocal void HndlSignal(int sig)
+ {
+ if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
+ if (sig == INFO_SIGNAL) { dumptable = 1; return; }
+ if (sig == SIGHUP) { hangup = 1; return; }
+ }
+
+mDNSlocal mStatus
+SetPublicSRV
+ (
+ DaemonInfo * d,
+ const char * name
+ )
+ {
+ DNameListElem * elem;
+ mStatus err = mStatus_NoError;
+
+ elem = ( DNameListElem* ) malloc( sizeof( DNameListElem ) );
+ require_action( elem, exit, err = mStatus_NoMemoryErr );
+ MakeDomainNameFromDNSNameString( &elem->name, name );
+ elem->next = d->public_names;
+ d->public_names = elem;
+
+exit:
+
+ return err;
+ }
+
+
+int main(int argc, char *argv[])
+ {
+ int started_via_launchd = 0;
+ DaemonInfo *d;
+ struct rlimit rlim;
+
+ Log("dnsextd starting");
+
+ d = malloc(sizeof(*d));
+ if (!d) { LogErr("main", "malloc"); exit(1); }
+ bzero(d, sizeof(DaemonInfo));
+
+ // Setup the public SRV record names
+
+ SetPublicSRV(d, "_dns-update._udp.");
+ SetPublicSRV(d, "_dns-llq._udp.");
+ SetPublicSRV(d, "_dns-update-tls._tcp.");
+ SetPublicSRV(d, "_dns-query-tls._tcp.");
+ SetPublicSRV(d, "_dns-llq-tls._tcp.");
+
+ // Setup signal handling
+
+ if (signal(SIGHUP, HndlSignal) == SIG_ERR) perror("Can't catch SIGHUP");
+ if (signal(SIGTERM, HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
+ if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
+ if (signal(SIGINT, HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
+ if (signal(SIGPIPE, SIG_IGN ) == SIG_ERR) perror("Can't ignore SIGPIPE");
+
+ // remove open file limit
+ rlim.rlim_max = RLIM_INFINITY;
+ rlim.rlim_cur = RLIM_INFINITY;
+ if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
+ {
+ LogErr("main", "setrlimit");
+ Log("Using default file descriptor resource limit");
+ }
+
+ if (!strcasecmp(argv[1], "-launchd"))
+ {
+ Log("started_via_launchd");
+ started_via_launchd = 1;
+ argv++;
+ argc--;
+ }
+ if (ProcessArgs(argc, argv, d) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
+
+ if (!foreground && !started_via_launchd)
+ {
+ if (daemon(0,0))
+ {
+ LogErr("main", "daemon");
+ foreground = 1;
+ }
+ }
+
+ if (InitLeaseTable(d) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
+ if (SetupSockets(d) < 0) { LogErr("main", "SetupSockets"); exit(1); }
+ if (SetUpdateSRV(d) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
+
+ Run(d);
+
+ Log("dnsextd stopping");
+
+ if (ClearUpdateSRV(d) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
+ free(d);
+ exit(0);
+ }
+
+
+// These are stubbed out implementations of up-call routines that the various platform support layers
+// call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
+// link this code in.
+//
+// It's an error for these routines to actually be called, so perhaps we should log any call
+// to them.
+void mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; }
+void mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; }
+void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
+ const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
+ const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
+ { ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
+DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
+ { ( void ) m; ( void ) d; ( void ) interface; ( void ) addr; ( void ) port; return(NULL); }
+void mDNS_AddSearchDomain(const domainname *const domain) { (void)domain; }
+void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
+ { ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
+mDNSs32 mDNS_Execute (mDNS *const m) { ( void ) m; return 0; }
+mDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
+mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
+void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
+ { ( void ) m; ( void ) set; ( void ) flapping; }
+const char * const mDNS_DomainTypeNames[1] = {};
+mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
+ const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
+ { ( void ) m; ( void ) question; ( void ) DomainType; ( void ) dom; ( void ) InterfaceID; ( void ) Callback; ( void ) Context; return 0; }
+mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
+mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
+ { ( void ) m; ( void ) set; ( void ) flapping; return 0; }
+void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
+void mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
+void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
+ { ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
+mStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
+mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
+ const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
+ { ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) AutoTunnel; return 0; }
+mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
+void mDNS_UpdateLLQs(mDNS * const m) { ( void ) m; }
+mDNS mDNSStorage;
+
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// For convenience when using the "strings" command, this is the last thing in the file
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
--- /dev/null
+// ----------------------------------------------------------------------------
+//
+// Instructions for /etc/dnsextd.conf (this file)
+//
+// In most cases, you should not need to change these default options in
+// the "options" section below. The dnsextd daemon will receive DNS packets
+// on port 53, and forward them on as appropriate to BIND on localhost:5030.
+//
+// You need to edit the "zone" statement below to give the name of your
+// dynamic zone that will be accepting Wide-Area Bonjour DNS updates.
+//
+// ----------------------------------------------------------------------------
+//
+// Instructions for /etc/named.conf
+//
+// In /etc/named.conf you will need to modify the "options" section to
+// tell BIND to accept packets from localhost:5030, like this:
+//
+// listen-on port 5030 { 127.0.0.1; };
+//
+// You also need a "zone" statement in /etc/named.conf to tell BIND the update
+// policy for your dynamic zone. For example, within a small closed private
+// network, you might allow anyone to perform updates. To do that, you just
+// permit any and all updates coming from dnsextd on the same machine:
+//
+// zone "my-dynamic-subdomain.company.com."
+// { type master; file "db.xxx"; allow-update { 127.0.0.1; }; };
+//
+// On a machine connected to the Internet or other large open network,
+// you'll want to limit updates to only users with keys. For example,
+// you could choose to allow anyone with a DNS key on your server to
+// perform updates in your dynamic zone, like this:
+//
+// key keyname. { algorithm hmac-md5; secret "abcdefghijklmnopqrstuv=="; };
+// zone "my-dynamic-subdomain.company.com." in
+// {
+// type master;
+// file "db.my-dynamic-subdomain.company.com";
+// update-policy { grant * wildcard *.my-dynamic-subdomain.company.com.; };
+// };
+//
+// You could use a single key which you give to all authorized users, but
+// it is better (though more work) to create a unique key for each user.
+//
+// ----------------------------------------------------------------------------
+
+options {
+// This defaults to: * port 53
+// listen-on port 53 { 192.168.2.10; 127.0.0.1; };
+// This defaults to: 127.0.0.1:5030
+// nameserver address 127.0.0.1 port 5030;
+// This defaults to: 5533
+// private port 5533;
+// This defaults to: 5352
+// llq port 5352;
+};
+
+zone "my-dynamic-subdomain.company.com." {
+ type public;
+};
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: dnsextd.h,v $
+Revision 1.5 2007/03/20 17:07:16 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
+
+Revision 1.4 2006/12/22 20:59:51 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.3 2006/11/18 05:01:33 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
+
+Revision 1.2 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.1 2006/07/06 00:09:05 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+
+
+ */
+
+
+#ifndef _dnsextd_h
+#define _dnsextd_h
+
+
+#include <mDNSEmbeddedAPI.h>
+#include <DNSCommon.h>
+#include <GenLinkedList.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+
+#define LLQ_TABLESIZE 1024 // !!!KRS make this dynamically growable
+
+
+typedef enum DNSZoneSpecType
+{
+ kDNSZonePublic,
+ kDNSZonePrivate
+} DNSZoneSpecType;
+
+
+typedef struct DNSZone
+{
+ domainname name;
+ DNSZoneSpecType type;
+ DomainAuthInfo * updateKeys; // linked list of keys for signing deletion updates
+ DomainAuthInfo * queryKeys; // linked list of keys for queries
+ struct DNSZone * next;
+} DNSZone;
+
+
+typedef struct
+ {
+ struct sockaddr_in src;
+ size_t len;
+ DNSZone * zone;
+ mDNSBool isZonePublic;
+ DNSMessage msg;
+ // Note: extra storage for oversized (TCP) messages goes here
+ } PktMsg;
+
+// lease table entry
+typedef struct RRTableElem
+ {
+ struct RRTableElem *next;
+ struct sockaddr_in cli; // client's source address
+ long expire; // expiration time, in seconds since epoch
+ domainname zone; // from zone field of update message
+ domainname name; // name of the record
+ CacheRecord rr; // last field in struct allows for allocation of oversized RRs
+ } RRTableElem;
+
+typedef enum
+ {
+ RequestReceived = 0,
+ ChallengeSent = 1,
+ Established = 2
+ } LLQState;
+
+typedef struct AnswerListElem
+ {
+ struct AnswerListElem *next;
+ domainname name;
+ mDNSu16 type;
+ CacheRecord *KnownAnswers; // All valid answers delivered to client
+ CacheRecord *EventList; // New answers (adds/removes) to be sent to client
+ int refcount;
+ mDNSBool UseTCP; // Use TCP if UDP would cause truncation
+ pthread_t tid; // Allow parallel list updates
+ } AnswerListElem;
+
+// llq table entry
+typedef struct LLQEntry
+ {
+ struct LLQEntry *next;
+ struct sockaddr_in cli; // clien'ts source address
+ domainname qname;
+ mDNSu16 qtype;
+ mDNSOpaque64 id;
+ LLQState state;
+ mDNSu32 lease; // original lease, in seconds
+ mDNSs32 expire; // expiration, absolute, in seconds since epoch
+ AnswerListElem *AnswerList;
+ } LLQEntry;
+
+
+typedef void (*EventCallback)( void * context );
+
+typedef struct EventSource
+ {
+ EventCallback callback;
+ void * context;
+ TCPSocket * sock;
+ int fd;
+ mDNSBool markedForDeletion;
+ struct EventSource * next;
+ } EventSource;
+
+
+// daemon-wide information
+typedef struct
+ {
+ // server variables - read only after initialization (no locking)
+ struct sockaddr_in addr; // the address we will bind to
+ struct sockaddr_in llq_addr; // the address we will receive llq requests on.
+ struct sockaddr_in ns_addr; // the real ns server address
+ int tcpsd; // listening TCP socket for dns requests
+ int udpsd; // listening UDP socket for dns requests
+ int tlssd; // listening TCP socket for private browsing
+ int llq_tcpsd; // listening TCP socket for llq service
+ int llq_udpsd; // listening UDP socket for llq service
+ DNameListElem * public_names; // list of public SRV names
+ DNSZone * zones;
+
+ // daemon variables - read only after initialization (no locking)
+ mDNSIPPort private_port; // listening port for private messages
+ mDNSIPPort llq_port; // listening port for llq
+
+ // lease table variables (locked via mutex after initialization)
+ RRTableElem **table; // hashtable for records with leases
+ pthread_mutex_t tablelock; // mutex for lease table
+ mDNSs32 nbuckets; // buckets allocated
+ mDNSs32 nelems; // elements in table
+
+ // LLQ table variables
+ LLQEntry *LLQTable[LLQ_TABLESIZE]; // !!!KRS change this and RRTable to use a common data structure
+ AnswerListElem *AnswerTable[LLQ_TABLESIZE];
+ int AnswerTableCount;
+ int LLQEventNotifySock; // Unix domain socket pair - update handling thread writes to EventNotifySock, which wakes
+ int LLQEventListenSock; // the main thread listening on EventListenSock, indicating that the zone has changed
+
+ GenLinkedList eventSources; // linked list of EventSource's
+ } DaemonInfo;
+
+
+int
+ParseConfig
+ (
+ DaemonInfo * d,
+ const char * file
+ );
+
+
+#endif
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: dnsextd_lexer.l,v $
+Revision 1.4 2007/05/25 20:01:43 cheshire
+<rdar://problem/5226767> /usr/bin/flex failures prevent mDNSResponder from building
+Only define "int yylineno" on flex 2.5.4 and earlier
+
+Revision 1.3 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.2 2006/07/06 20:41:14 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Use derived filename "dnsextd_parser.h" instead of "dnsextd_parser.y.h"
+
+Revision 1.1 2006/07/06 00:09:05 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+
+ */
+
+%{
+#include <string.h>
+#include <stdio.h>
+#include "dnsextd_parser.h"
+
+
+extern YYSTYPE yylval;
+
+/* Mac OS X 10.4 has flex version 2.5.4, which doesn't define yylineno for us */
+/* Mac OS X 10.5 has flex version 2.5.33, which does define yylineno */
+#if YY_FLEX_MAJOR_VERSION <= 2 && YY_FLEX_MINOR_VERSION <= 5 && YY_FLEX_SUBMINOR_VERSION <= 4
+int yylineno = 1;
+#endif
+
+#define YY_NO_UNPUT
+
+int yylex(void);
+
+static char*
+StripQuotes
+ (
+ const char * string
+ )
+{
+ char * dup;
+
+ dup = strdup( string + 1);
+
+ dup[ strlen( dup ) - 1 ] = '\0';
+
+ return dup;
+}
+
+
+%}
+
+%%
+
+options return OPTIONS;
+listen-on return LISTEN_ON;
+nameserver return NAMESERVER;
+port return PORT;
+address return ADDRESS;
+llq return LLQ;
+public return PUBLIC;
+private return PRIVATE;
+key return KEY;
+allow-update return ALLOWUPDATE;
+allow-query return ALLOWQUERY;
+algorithm return ALGORITHM;
+secret return SECRET;
+zone return ZONE;
+type return TYPE;
+allow return ALLOW;
+\{ return OBRACE;
+\} return EBRACE;
+; return SEMICOLON;
+IN return IN;
+\* yylval.string = strdup(yytext); return WILDCARD;
+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ yylval.string = strdup(yytext); return DOTTED_DECIMAL_ADDRESS;
+[0123456789]+ yylval.number = atoi(yytext); return NUMBER;
+[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)* yylval.string = strdup(yytext); return HOSTNAME;
+[a-zA-Z0-9\.]+([a-zA-Z0-9\.]+)* yylval.string = strdup(yytext); return DOMAINNAME;
+\"([^"\\\r\n]*(\\.[^"\\\r\n]*)*)\" yylval.string = StripQuotes(yytext); return QUOTEDSTRING;
+[\/][\/].* /* ignore C++ style comments */;
+\n yylineno++; /* ignore EOL */;
+[ \t]+ /* ignore whitespace */;
+%%
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: dnsextd_parser.y,v $
+Revision 1.8 2007/03/21 19:47:50 cheshire
+<rdar://problem/4789463> Leak: On error path in ParseConfig
+
+Revision 1.7 2007/01/17 17:38:13 cheshire
+Need to include stdlib.h for malloc/free
+
+Revision 1.6 2006/12/22 20:59:51 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
+
+Revision 1.5 2006/10/20 05:47:09 herscher
+Set the DNSZone pointer to NULL in ParseConfig() before parsing the configuration file.
+
+Revision 1.4 2006/08/16 00:35:39 mkrochma
+<rdar://problem/4386944> Get rid of NotAnInteger references
+
+Revision 1.3 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.2 2006/07/14 02:03:37 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+private_port and llq_port should use htons, not htonl
+
+Revision 1.1 2006/07/06 00:09:05 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+
+ */
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mDNSEmbeddedAPI.h>
+#include <DebugServices.h>
+#include "dnsextd.h"
+
+void yyerror( const char* error );
+int yylex(void);
+
+
+typedef struct StringListElem
+{
+ char * string;
+ struct StringListElem * next;
+} StringListElem;
+
+
+typedef struct OptionsInfo
+{
+ char server_address[ 256 ];
+ int server_port;
+ char source_address[ 256 ];
+ int source_port;
+ int private_port;
+ int llq_port;
+} OptionsInfo;
+
+
+typedef struct ZoneInfo
+{
+ char name[ 256 ];
+ char certificate_name[ 256 ];
+ char allow_clients_file[ 256 ];
+ char allow_clients[ 256 ];
+ char key[ 256 ];
+} ZoneInfo;
+
+
+typedef struct KeySpec
+{
+ char name[ 256 ];
+ char algorithm[ 256 ];
+ char secret[ 256 ];
+ struct KeySpec * next;
+} KeySpec;
+
+
+typedef struct ZoneSpec
+{
+ char name[ 256 ];
+ DNSZoneSpecType type;
+ StringListElem * allowUpdate;
+ StringListElem * allowQuery;
+ char key[ 256 ];
+ struct ZoneSpec * next;
+} ZoneSpec;
+
+
+static StringListElem * g_stringList = NULL;
+static KeySpec * g_keys;
+static ZoneSpec * g_zones;
+static ZoneSpec g_zoneSpec;
+static const char * g_filename;
+
+#define YYPARSE_PARAM context
+
+void
+SetupOptions
+ (
+ OptionsInfo * info,
+ void * context
+ );
+
+%}
+
+%union
+{
+ int number;
+ char * string;
+}
+
+%token OPTIONS
+%token LISTEN_ON
+%token NAMESERVER
+%token PORT
+%token ADDRESS
+%token LLQ
+%token PUBLIC
+%token PRIVATE
+%token ALLOWUPDATE
+%token ALLOWQUERY
+%token KEY
+%token ALGORITHM
+%token SECRET
+%token ISSUER
+%token SERIAL
+%token ZONE
+%token TYPE
+%token ALLOW
+%token OBRACE
+%token EBRACE
+%token SEMICOLON
+%token IN
+%token <string> DOTTED_DECIMAL_ADDRESS
+%token <string> WILDCARD
+%token <string> DOMAINNAME
+%token <string> HOSTNAME
+%token <string> QUOTEDSTRING
+%token <number> NUMBER
+
+%type <string> addressstatement
+%type <string> networkaddress
+
+%%
+
+commands:
+ |
+ commands command SEMICOLON
+ ;
+
+
+command:
+ options_set
+ |
+ zone_set
+ |
+ key_set
+ ;
+
+
+options_set:
+ OPTIONS optionscontent
+ {
+ // SetupOptions( &g_optionsInfo, context );
+ }
+ ;
+
+optionscontent:
+ OBRACE optionsstatements EBRACE
+ ;
+
+optionsstatements:
+ |
+ optionsstatements optionsstatement SEMICOLON
+ ;
+
+
+optionsstatement:
+ statements
+ |
+ LISTEN_ON addresscontent
+ {
+ }
+ |
+ LISTEN_ON PORT NUMBER addresscontent
+ {
+ }
+ |
+ NAMESERVER ADDRESS networkaddress
+ {
+ }
+ |
+ NAMESERVER ADDRESS networkaddress PORT NUMBER
+ {
+ }
+ |
+ PRIVATE PORT NUMBER
+ {
+ ( ( DaemonInfo* ) context )->private_port = mDNSOpaque16fromIntVal( NUMBER );
+ }
+ |
+ LLQ PORT NUMBER
+ {
+ ( ( DaemonInfo* ) context )->llq_port = mDNSOpaque16fromIntVal( NUMBER );
+ }
+ ;
+
+key_set:
+ KEY QUOTEDSTRING OBRACE SECRET QUOTEDSTRING SEMICOLON EBRACE
+ {
+ KeySpec * keySpec;
+
+ keySpec = ( KeySpec* ) malloc( sizeof( KeySpec ) );
+
+ if ( !keySpec )
+ {
+ LogMsg("ERROR: memory allocation failure");
+ YYABORT;
+ }
+
+ strncpy( keySpec->name, $2, sizeof( keySpec->name ) );
+ strncpy( keySpec->secret, $5, sizeof( keySpec->secret ) );
+
+ keySpec->next = g_keys;
+ g_keys = keySpec;
+ }
+ ;
+
+zone_set:
+ ZONE QUOTEDSTRING zonecontent
+ {
+ ZoneSpec * zoneSpec;
+
+ zoneSpec = ( ZoneSpec* ) malloc( sizeof( ZoneSpec ) );
+
+ if ( !zoneSpec )
+ {
+ LogMsg("ERROR: memory allocation failure");
+ YYABORT;
+ }
+
+ strncpy( zoneSpec->name, $2, sizeof( zoneSpec->name ) );
+ zoneSpec->type = g_zoneSpec.type;
+ strcpy( zoneSpec->key, g_zoneSpec.key );
+ zoneSpec->allowUpdate = g_zoneSpec.allowUpdate;
+ zoneSpec->allowQuery = g_zoneSpec.allowQuery;
+
+ zoneSpec->next = g_zones;
+ g_zones = zoneSpec;
+ }
+ |
+ ZONE QUOTEDSTRING IN zonecontent
+ {
+ ZoneSpec * zoneSpec;
+
+ zoneSpec = ( ZoneSpec* ) malloc( sizeof( ZoneSpec ) );
+
+ if ( !zoneSpec )
+ {
+ LogMsg("ERROR: memory allocation failure");
+ YYABORT;
+ }
+
+ strncpy( zoneSpec->name, $2, sizeof( zoneSpec->name ) );
+ zoneSpec->type = g_zoneSpec.type;
+ strcpy( zoneSpec->key, g_zoneSpec.key );
+ zoneSpec->allowUpdate = g_zoneSpec.allowUpdate;
+ zoneSpec->allowQuery = g_zoneSpec.allowQuery;
+
+ zoneSpec->next = g_zones;
+ g_zones = zoneSpec;
+ }
+ ;
+
+zonecontent:
+ OBRACE zonestatements EBRACE
+
+zonestatements:
+ |
+ zonestatements zonestatement SEMICOLON
+ ;
+
+zonestatement:
+ TYPE PUBLIC
+ {
+ g_zoneSpec.type = kDNSZonePublic;
+ }
+ |
+ TYPE PRIVATE
+ {
+ g_zoneSpec.type = kDNSZonePrivate;
+ }
+ |
+ ALLOWUPDATE keycontent
+ {
+ g_zoneSpec.allowUpdate = g_stringList;
+ g_stringList = NULL;
+ }
+ |
+ ALLOWQUERY keycontent
+ {
+ g_zoneSpec.allowQuery = g_stringList;
+ g_stringList = NULL;
+ }
+ ;
+
+addresscontent:
+ OBRACE addressstatements EBRACE
+ {
+ }
+
+addressstatements:
+ |
+ addressstatements addressstatement SEMICOLON
+ {
+ }
+ ;
+
+addressstatement:
+ DOTTED_DECIMAL_ADDRESS
+ {
+ }
+ ;
+
+
+keycontent:
+ OBRACE keystatements EBRACE
+ {
+ }
+
+keystatements:
+ |
+ keystatements keystatement SEMICOLON
+ {
+ }
+ ;
+
+keystatement:
+ KEY DOMAINNAME
+ {
+ StringListElem * elem;
+
+ elem = ( StringListElem* ) malloc( sizeof( StringListElem ) );
+
+ if ( !elem )
+ {
+ LogMsg("ERROR: memory allocation failure");
+ YYABORT;
+ }
+
+ elem->string = $2;
+
+ elem->next = g_stringList;
+ g_stringList = elem;
+ }
+ ;
+
+
+networkaddress:
+ DOTTED_DECIMAL_ADDRESS
+ |
+ HOSTNAME
+ |
+ WILDCARD
+ ;
+
+block:
+ OBRACE zonestatements EBRACE SEMICOLON
+ ;
+
+statements:
+ |
+ statements statement
+ ;
+
+statement:
+ block
+ {
+ $<string>$ = NULL;
+ }
+ |
+ QUOTEDSTRING
+ {
+ $<string>$ = $1;
+ }
+%%
+
+int yywrap(void);
+
+extern int yylineno;
+
+void yyerror( const char *str )
+{
+ fprintf( stderr,"%s:%d: error: %s\n", g_filename, yylineno, str );
+}
+
+int yywrap()
+{
+ return 1;
+}
+
+
+int
+ParseConfig
+ (
+ DaemonInfo * d,
+ const char * file
+ )
+ {
+ extern FILE * yyin;
+ DNSZone * zone;
+ DomainAuthInfo * key;
+ KeySpec * keySpec;
+ ZoneSpec * zoneSpec;
+ int err = 0;
+
+ g_filename = file;
+
+ // Tear down the current zone specifiers
+
+ zone = d->zones;
+
+ while ( zone )
+ {
+ DNSZone * next = zone->next;
+
+ key = zone->updateKeys;
+
+ while ( key )
+ {
+ DomainAuthInfo * nextKey = key->next;
+
+ free( key );
+
+ key = nextKey;
+ }
+
+ key = zone->queryKeys;
+
+ while ( key )
+ {
+ DomainAuthInfo * nextKey = key->next;
+
+ free( key );
+
+ key = nextKey;
+ }
+
+ free( zone );
+
+ zone = next;
+ }
+
+ d->zones = NULL;
+
+ yyin = fopen( file, "r" );
+ require_action( yyin, exit, err = 0 );
+
+ err = yyparse( ( void* ) d );
+ require_action( !err, exit, err = 1 );
+
+ for ( zoneSpec = g_zones; zoneSpec; zoneSpec = zoneSpec->next )
+ {
+ StringListElem * elem;
+ mDNSu8 * ok;
+
+ zone = ( DNSZone* ) malloc( sizeof( DNSZone ) );
+ require_action( zone, exit, err = 1 );
+ memset( zone, 0, sizeof( DNSZone ) );
+
+ zone->next = d->zones;
+ d->zones = zone;
+
+ // Fill in the domainname
+
+ ok = MakeDomainNameFromDNSNameString( &zone->name, zoneSpec->name );
+ require_action( ok, exit, err = 1 );
+
+ // Fill in the type
+
+ zone->type = zoneSpec->type;
+
+ // Fill in the allow-update keys
+
+ for ( elem = zoneSpec->allowUpdate; elem; elem = elem->next )
+ {
+ mDNSBool found = mDNSfalse;
+
+ for ( keySpec = g_keys; keySpec; keySpec = keySpec->next )
+ {
+ if ( strcmp( elem->string, keySpec->name ) == 0 )
+ {
+ DomainAuthInfo * authInfo = malloc( sizeof( DomainAuthInfo ) );
+ mDNSs32 keylen;
+ require_action( authInfo, exit, err = 1 );
+ memset( authInfo, 0, sizeof( DomainAuthInfo ) );
+
+ ok = MakeDomainNameFromDNSNameString( &authInfo->keyname, keySpec->name );
+ if (!ok) { free(authInfo); err = 1; goto exit; }
+
+ keylen = DNSDigest_ConstructHMACKeyfromBase64( authInfo, keySpec->secret );
+ if (keylen < 0) { free(authInfo); err = 1; goto exit; }
+
+ authInfo->next = zone->updateKeys;
+ zone->updateKeys = authInfo;
+
+ found = mDNStrue;
+
+ break;
+ }
+ }
+
+ // Log this
+ require_action( found, exit, err = 1 );
+ }
+
+ // Fill in the allow-query keys
+
+ for ( elem = zoneSpec->allowQuery; elem; elem = elem->next )
+ {
+ mDNSBool found = mDNSfalse;
+
+ for ( keySpec = g_keys; keySpec; keySpec = keySpec->next )
+ {
+ if ( strcmp( elem->string, keySpec->name ) == 0 )
+ {
+ DomainAuthInfo * authInfo = malloc( sizeof( DomainAuthInfo ) );
+ mDNSs32 keylen;
+ require_action( authInfo, exit, err = 1 );
+ memset( authInfo, 0, sizeof( DomainAuthInfo ) );
+
+ ok = MakeDomainNameFromDNSNameString( &authInfo->keyname, keySpec->name );
+ if (!ok) { free(authInfo); err = 1; goto exit; }
+
+ keylen = DNSDigest_ConstructHMACKeyfromBase64( authInfo, keySpec->secret );
+ if (keylen < 0) { free(authInfo); err = 1; goto exit; }
+
+ authInfo->next = zone->queryKeys;
+ zone->queryKeys = authInfo;
+
+ found = mDNStrue;
+
+ break;
+ }
+ }
+
+ // Log this
+ require_action( found, exit, err = 1 );
+ }
+ }
+
+exit:
+
+ return err;
+ }
+
+
+void
+SetupOptions
+ (
+ OptionsInfo * info,
+ void * context
+ )
+ {
+ DaemonInfo * d = ( DaemonInfo* ) context;
+
+ if ( strlen( info->source_address ) )
+ {
+ inet_pton( AF_INET, info->source_address, &d->addr.sin_addr );
+ }
+
+ if ( info->source_port )
+ {
+ d->addr.sin_port = htons( ( mDNSu16 ) info->source_port );
+ }
+
+ if ( strlen( info->server_address ) )
+ {
+ inet_pton( AF_INET, info->server_address, &d->ns_addr.sin_addr );
+ }
+
+ if ( info->server_port )
+ {
+ d->ns_addr.sin_port = htons( ( mDNSu16 ) info->server_port );
+ }
+
+ if ( info->private_port )
+ {
+ d->private_port = mDNSOpaque16fromIntVal( info->private_port );
+ }
+
+ if ( info->llq_port )
+ {
+ d->llq_port = mDNSOpaque16fromIntVal( info->llq_port );
+ }
+ }
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004, Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Change History (most recent first):
$Log: dnssd_clientlib.c,v $
+Revision 1.17 2007/10/02 19:36:04 cheshire
+<rdar://problem/5516444> TXTRecordGetValuePtr should be case-insenstive
+
+Revision 1.16 2007/09/18 19:09:02 cheshire
+<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
+
+Revision 1.15 2007/07/28 00:00:43 cheshire
+Renamed CompileTimeAssertionCheck structure for consistency with others
+
+Revision 1.14 2007/03/20 17:07:16 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
+
+Revision 1.13 2007/02/27 00:25:03 cheshire
+<rdar://problem/5010640> DNSServiceConstructFullName() doesn't handle empty string for instance name
+
+Revision 1.12 2007/02/07 19:32:00 cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
+
+Revision 1.11 2006/08/14 23:05:53 cheshire
+Added "tab-width" emacs header line
+
Revision 1.10 2005/04/06 02:06:56 shersche
Add DNSSD_API macro to TXTRecord API calls
{
uint8_t *x = p;
p += 1 + p[0];
- if (p <= e && *keylen <= x[0] && !strncmp(key, (char*)x+1, *keylen))
+ if (p <= e && *keylen <= x[0] && !strncasecmp(key, (char*)x+1, *keylen))
if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
}
return(NULL);
const char *r = regtype;
const char *d = domain;
- if (service)
+ if (service && *service)
{
- while(*s)
+ while (*s)
{
c = (unsigned char)*s++;
if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals
len = (unsigned long) strlen(regtype);
if (DomainEndsInDot(regtype)) len--;
if (len < 6) return -1; // regtype must be at least "x._udp" or "x._tcp"
- if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
- while(*r) *fn++ = *r++;
+ if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return -1;
+ while (*r) *fn++ = *r++;
if (!DomainEndsInDot(regtype)) *fn++ = '.';
if (!domain || !domain[0]) return -1;
- while(*d) *fn++ = *d++;
+ while (*d) *fn++ = *d++;
if (!DomainEndsInDot(domain)) *fn++ = '.';
*fn = '\0';
return 0;
// The opaque storage defined in the public dns_sd.h header is 16 bytes;
// make sure we don't exceed that.
-struct dnssd_clientlib_CompileTimeAssertionCheck
+struct CompileTimeAssertionCheck_dnssd_clientlib
{
char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1];
};
}
return(kDNSServiceErr_Invalid);
}
+
+/*********************************************************************************************
+ *
+ * SCCS-compatible version string
+ *
+ *********************************************************************************************/
+
+// For convenience when using the "strings" command, this is the last thing in the file
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
* This file defines a simple shim layer between a client calling the "/usr/include/dns_sd.h" APIs
* and an implementation of mDNSCore ("mDNSEmbeddedAPI.h" APIs) in the same address space.
Change History (most recent first):
$Log: dnssd_clientshim.c,v $
+Revision 1.15 2007/07/27 19:30:41 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
+
+Revision 1.14 2007/07/17 19:15:26 cheshire
+<rdar://problem/5297410> Crash in DNSServiceRegister() in dnssd_clientshim.c
+
+Revision 1.13 2007/01/04 20:57:49 cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
+
+Revision 1.12 2006/12/19 22:43:55 cheshire
+Fix compiler warnings
+
+Revision 1.11 2006/10/27 01:30:23 cheshire
+Need explicitly to set ReturnIntermed = mDNSfalse
+
+Revision 1.10 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.9 2006/07/24 23:45:55 cheshire
+<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
+
Revision 1.8 2004/12/16 20:47:34 cheshire
<rdar://problem/3324626> Cache memory management improvements
mDNSBool autoname; // Set if this name is tied to the Computer Name
mDNSBool autorename; // Set if we just got a name conflict and now need to automatically pick a new name
domainlabel name;
+ domainname host;
ServiceRecordSet s;
} mDNS_DirectOP_Register;
(void)interfaceIndex; // Unused
// Check parameters
+ if (!name) name = "";
if (!name[0]) n = mDNSStorage.nicelabel;
else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
x->autoname = (!name[0]);
x->autorename = mDNSfalse;
x->name = n;
+ x->host = h;
// Do the operation
err = mDNS_RegisterService(&mDNSStorage, &x->s,
&x->name, &t, &d, // Name, type, domain
- &h, port, // Host and port
+ &x->host, port, // Host and port
txtRecord, txtLen, // TXT data, length
SubTypes, NumSubTypes, // Subtypes
mDNSInterface_Any, // Interface ID
mDNSPlatformMemFree(x);
}
-mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0;
domainlabel name;
mDNSPlatformMemFree(x);
}
-mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)question->QuestionContext;
(void)m; // Unused
ConvertDomainNameToCString(answer->name, fullname);
ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost);
x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost,
- x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (char*)x->TXT->rdata->u.txt.c, x->context);
+ x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (unsigned char*)x->TXT->rdata->u.txt.c, x->context);
}
}
}
x->qSRV.LongLived = mDNSfalse;
x->qSRV.ExpectUnique = mDNStrue;
x->qSRV.ForceMCast = mDNSfalse;
+ x->qSRV.ReturnIntermed = mDNSfalse;
x->qSRV.QuestionCallback = FoundServiceInfo;
x->qSRV.QuestionContext = x;
x->qTXT.LongLived = mDNSfalse;
x->qTXT.ExpectUnique = mDNStrue;
x->qTXT.ForceMCast = mDNSfalse;
+ x->qTXT.ReturnIntermed = mDNSfalse;
x->qTXT.QuestionCallback = FoundServiceInfo;
x->qTXT.QuestionContext = x;
mDNSPlatformMemFree(x);
}
-mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext;
char fullname[MAX_ESCAPED_DOMAIN_NAME];
x->q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
x->q.ExpectUnique = mDNSfalse;
x->q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
+ x->q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
x->q.QuestionCallback = DNSServiceQueryRecordResponse;
x->q.QuestionContext = x;
// is run against this Extension, it will get a reasonable error code instead of just
// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
#if !MDNS_BUILDINGSTUBLIBRARY
-void DNSServiceReconfirmRecord
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
(
DNSServiceFlags flags,
uint32_t interfaceIndex,
(void)rrclass; // Unused
(void)rdlen; // Unused
(void)rdata; // Unused
+ return(kDNSServiceErr_Unsupported);
}
#endif
*
* Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Change History (most recent first):
+ Change History (most recent first):
$Log: dnssd_clientstub.c,v $
-Revision 1.48 2005/06/30 18:01:00 shersche
-<rdar://problem/4096913> Clients shouldn't wait ten seconds to connect to mDNSResponder
+Revision 1.93 2007/10/10 00:48:54 cheshire
+<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
-Revision 1.47 2005/03/31 02:19:56 cheshire
-<rdar://problem/4021486> Fix build warnings
-Reviewed by: Scott Herscher
+Revision 1.92 2007/10/06 03:44:44 cheshire
+Testing code for <rdar://problem/5526374> kqueue does not get a kevent to wake it up when a control message arrives on a socket
-Revision 1.46 2005/03/21 00:39:31 shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
+Revision 1.91 2007/10/04 20:53:59 cheshire
+Improved debugging message when sendmsg fails
-Revision 1.45 2005/02/01 01:25:06 shersche
-Define sleep() to be Sleep() for Windows compatibility
+Revision 1.90 2007/09/30 00:09:27 cheshire
+<rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
-Revision 1.44 2005/01/27 22:57:56 cheshire
-Fix compile errors on gcc4
+Revision 1.89 2007/09/19 23:53:12 cheshire
+Fixed spelling mistake in comment
-Revision 1.43 2005/01/27 00:02:29 cheshire
-<rdar://problem/3947461> Handle case where client runs before daemon has finished launching
+Revision 1.88 2007/09/07 23:18:27 cheshire
+<rdar://problem/5467542> Change "client_context" to be an incrementing 64-bit counter
-Revision 1.42 2005/01/11 02:01:02 shersche
-Use dnssd_close() rather than close() for Windows compatibility
+Revision 1.87 2007/09/07 22:50:09 cheshire
+Added comment explaining moreptr field in DNSServiceOp structure
-Revision 1.41 2004/12/23 17:34:26 ksekar
-<rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
+Revision 1.86 2007/09/07 20:21:22 cheshire
+<rdar://problem/5462371> Make DNSSD library more resilient
+Add more comments explaining the moreptr/morebytes logic; don't allow DNSServiceRefSockFD or
+DNSServiceProcessResult for subordinate DNSServiceRefs created using kDNSServiceFlagsShareConnection
-Revision 1.40 2004/11/23 03:39:47 cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
+Revision 1.85 2007/09/06 21:43:23 cheshire
+<rdar://problem/5462371> Make DNSSD library more resilient
+Allow DNSServiceRefDeallocate from within DNSServiceProcessResult callback
-Revision 1.39 2004/11/12 03:22:00 rpantos
-rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
+Revision 1.84 2007/09/06 18:31:47 cheshire
+<rdar://problem/5462371> Make DNSSD library more resilient against client programming errors
-Revision 1.38 2004/11/02 02:51:23 cheshire
-<rdar://problem/3526342> Remove overly-restrictive flag checks
+Revision 1.83 2007/08/28 20:45:45 cheshire
+Typo: ctrl_path needs to be 64 bytes, not 44 bytes
-Revision 1.37 2004/10/14 01:43:35 cheshire
-Fix opaque port passing problem
+Revision 1.82 2007/08/28 19:53:52 cheshire
+<rdar://problem/5437423> Bonjour failures when /tmp is not writable (e.g. when booted from installer disc)
-Revision 1.36 2004/10/06 02:22:19 cheshire
-Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
+Revision 1.81 2007/07/27 00:03:20 cheshire
+Fixed compiler warnings that showed up now we're building optimized ("-Os")
-Revision 1.35 2004/10/01 22:15:55 rpantos
-rdar://problem/3824265: Replace APSL in client lib with BSD license.
+Revision 1.80 2007/07/23 22:12:53 cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-Revision 1.34 2004/09/17 22:36:13 cheshire
-Add comment explaining that deliver_request frees the message it sends
+Revision 1.79 2007/07/23 19:58:24 cheshire
+<rdar://problem/5351640> Library: Leak in DNSServiceRefDeallocate
-Revision 1.33 2004/09/17 01:17:31 ksekar
-Remove double-free of msg header, freed automatically by deliver_request()
+Revision 1.78 2007/07/12 20:42:27 cheshire
+<rdar://problem/5280735> If daemon is killed, return kDNSServiceErr_ServiceNotRunning
+to clients instead of kDNSServiceErr_Unknown
-Revision 1.32 2004/09/17 01:08:55 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.77 2007/07/02 23:07:13 cheshire
+<rdar://problem/5308280> Reduce DNS-SD client syslog error messages
-Revision 1.31 2004/09/16 23:37:19 cheshire
-Free hdr before returning
+Revision 1.76 2007/06/22 20:12:18 cheshire
+<rdar://problem/5277024> Leak in DNSServiceRefDeallocate
-Revision 1.30 2004/09/16 23:14:24 cheshire
-Changes for Windows compatibility
+Revision 1.75 2007/05/23 18:59:22 cheshire
+Remove unnecessary IPC_FLAGS_REUSE_SOCKET
-Revision 1.29 2004/09/16 21:46:38 ksekar
-<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
+Revision 1.74 2007/05/22 18:28:38 cheshire
+Fixed compile errors in posix build
-Revision 1.28 2004/08/11 17:10:04 cheshire
-Fix signed/unsigned warnings
+Revision 1.73 2007/05/22 01:20:47 cheshire
+To determine current operation, need to check hdr->op, not sdr->op
-Revision 1.27 2004/08/11 00:54:16 cheshire
-Change "hdr->op.request_op" to just "hdr->op"
+Revision 1.72 2007/05/22 01:07:42 cheshire
+<rdar://problem/3563675> API: Need a way to get version/feature information
-Revision 1.26 2004/07/26 06:07:27 shersche
-fix bugs when using an error socket to communicate with the daemon
+Revision 1.71 2007/05/18 23:55:22 cheshire
+<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
-Revision 1.25 2004/07/26 05:54:02 shersche
-DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
+Revision 1.70 2007/05/17 20:58:22 cheshire
+<rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
-Revision 1.24 2004/07/20 06:46:21 shersche
-<rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
-Bug #: 3730123
+Revision 1.69 2007/05/16 16:58:27 cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
+As long as select indicates that data is waiting, loop within DNSServiceProcessResult delivering additional results
-Revision 1.23 2004/06/29 00:48:38 cheshire
-Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
-use an explicit while() loop instead.
+Revision 1.68 2007/05/16 01:06:52 cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-Revision 1.22 2004/06/26 03:16:34 shersche
-clean up warning messages on Win32 platform
+Revision 1.67 2007/05/15 21:57:16 cheshire
+<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
+assuming that all negative values (or zero!) are invalid socket numbers
-Submitted by: herscher
+Revision 1.66 2007/03/27 22:23:04 cheshire
+Add "dnssd_clientstub" prefix onto syslog messages
-Revision 1.21 2004/06/18 04:53:56 rpantos
-Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
+Revision 1.65 2007/03/21 22:25:23 cheshire
+<rdar://problem/4172796> Remove client retry logic now that mDNSResponder uses launchd for its Unix Domain Socket
-Revision 1.20 2004/06/12 00:50:22 cheshire
-Changes for Windows compatibility
+Revision 1.64 2007/03/21 19:01:56 cheshire
+<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-Revision 1.19 2004/05/25 18:29:33 cheshire
-Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
-so that it's also accessible to dnssd_clientshim.c (single address space) clients.
+Revision 1.63 2007/03/12 21:48:21 cheshire
+<rdar://problem/5000162> Scary unlink errors in system.log
+Code was using memory after it had been freed
-Revision 1.18 2004/05/18 23:51:27 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.62 2007/02/28 01:44:30 cheshire
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-Revision 1.17 2004/05/06 18:42:58 ksekar
-General dns_sd.h API cleanup, including the following radars:
-<rdar://problem/3592068>: Remove flags with zero value
-<rdar://problem/3479569>: Passing in NULL causes a crash.
+Revision 1.61 2007/02/09 03:09:42 cheshire
+<rdar://problem/3869251> Cleanup: Stop returning kDNSServiceErr_Unknown so often
+<rdar://problem/4177924> API: Should return kDNSServiceErr_ServiceNotRunning
-Revision 1.16 2004/03/12 22:00:37 cheshire
-Added: #include <sys/socket.h>
+Revision 1.60 2007/02/08 20:33:44 cheshire
+<rdar://problem/4985095> Leak on error path in DNSServiceProcessResult
-Revision 1.15 2004/01/20 18:36:29 ksekar
-Propagated Libinfo fix for <rdar://problem/3483971>: SU:
-DNSServiceUpdateRecord() doesn't allow you to update the TXT record
-into TOT mDNSResponder.
+Revision 1.59 2007/01/05 08:30:55 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.14 2004/01/19 22:39:17 cheshire
-Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
-use an explicit while() loop instead. (In any case, this should only make a difference
-with non-blocking sockets, which we don't use on the client side right now.)
+Revision 1.58 2006/10/27 00:38:22 cheshire
+Strip accidental trailing whitespace from lines
-Revision 1.13 2004/01/19 21:46:52 cheshire
-Fix compiler warning
+Revision 1.57 2006/09/30 01:06:54 cheshire
+Protocol field should be uint32_t
-Revision 1.12 2003/12/23 20:46:47 ksekar
-<rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
+Revision 1.56 2006/09/27 00:44:16 herscher
+<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-Revision 1.11 2003/12/08 21:11:42 rpantos
-Changes necessary to support mDNSResponder on Linux.
+Revision 1.55 2006/09/26 01:52:01 herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-Revision 1.10 2003/10/13 23:50:53 ksekar
-Updated dns_sd clientstub files to bring copies in synch with
-top-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed,
-and comments in dns_sd.h are improved.
+Revision 1.54 2006/09/21 21:34:09 cheshire
+<rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
-Revision 1.9 2003/08/15 21:30:39 cheshire
-Bring up to date with LibInfo version
+Revision 1.53 2006/09/07 04:43:12 herscher
+Fix compile error on Win32 platform by moving inclusion of syslog.h
-Revision 1.8 2003/08/13 23:54:52 ksekar
-Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
+Revision 1.52 2006/08/15 23:04:21 mkrochma
+<rdar://problem/4090354> Client should be able to specify service name w/o callback
-Revision 1.7 2003/08/12 19:56:25 cheshire
-Update to APSL 2.0
+Revision 1.51 2006/07/24 23:45:55 cheshire
+<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
- */
+Revision 1.50 2006/06/28 08:22:27 cheshire
+<rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog
+
+Revision 1.49 2006/06/28 07:58:59 cheshire
+Minor textual tidying
+
+*/
#include <errno.h>
#include <stdlib.h>
-#if defined(_WIN32)
-#include <winsock2.h>
-#include <windows.h>
-#define sockaddr_mdns sockaddr_in
-#define AF_MDNS AF_INET
-extern BOOL
-IsSystemServiceDisabled();
-#else
-#include <sys/time.h>
-#include <sys/socket.h>
-#define sockaddr_mdns sockaddr_un
-#define AF_MDNS AF_LOCAL
-#endif
#include "dnssd_ipc.h"
#if defined(_WIN32)
-// disable warning: "'type cast' : from data pointer 'void *' to
-// function pointer"
-#pragma warning(disable:4055)
-// disable warning: "nonstandard extension, function/data pointer
-// conversion in expression"
-#pragma warning(disable:4152)
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ #include <windows.h>
+
+ #define sockaddr_mdns sockaddr_in
+ #define AF_MDNS AF_INET
+
+ // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
+ #pragma warning(disable:4055)
+
+ // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
+ #pragma warning(disable:4152)
+
+ extern BOOL IsSystemServiceDisabled();
+
+ #define sleep(X) Sleep((X) * 1000)
+
+ static int g_initWinsock = 0;
+
+#else
-#define sleep(X) Sleep((X) * 1000)
+ #include <sys/time.h>
+ #include <sys/socket.h>
+ #include <syslog.h>
+
+ #define sockaddr_mdns sockaddr_un
+ #define AF_MDNS AF_LOCAL
-static int g_initWinsock = 0;
#endif
+// <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
+
+#define DNSSD_CLIENT_MAXTRIES 4
+
+// Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
+//#define USE_NAMED_ERROR_RETURN_SOCKET 1
+
+#ifndef CTL_PATH_PREFIX
+#define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
+#endif
+
+typedef struct
+ {
+ ipc_msg_hdr ipc_hdr;
+ DNSServiceFlags cb_flags;
+ uint32_t cb_interface;
+ DNSServiceErrorType cb_err;
+ } CallbackHeader;
+
+typedef struct _DNSServiceRef_t DNSServiceOp;
+typedef struct _DNSRecordRef_t DNSRecord;
+
+// client stub callback to process message from server and deliver results to client application
+typedef void (*ProcessReplyFn)(DNSServiceOp *sdr, CallbackHeader *cbh, char *msg, char *end);
+
+#define ValidatorBits 0x12345678
+#define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
+
+// When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
+// For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
+// For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
+struct _DNSServiceRef_t
+ {
+ DNSServiceOp *next; // For shared connection
+ DNSServiceOp *primary; // For shared connection
+ dnssd_sock_t sockfd; // Connected socket between client and daemon
+ dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
+ client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
+ // unique within the scope of the same shared parent DNSServiceRef
+ uint32_t op; // request_op_t or reply_op_t
+ uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
+ uint32_t logcounter; // Counter used to control number of syslog messages we write
+ int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
+ ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
+ void *AppCallback; // Client callback function and context
+ void *AppContext;
+ };
+
+struct _DNSRecordRef_t
+ {
+ void *AppContext;
+ DNSServiceRegisterRecordReply AppCallback;
+ DNSRecordRef recref;
+ uint32_t record_index; // index is unique to the ServiceDiscoveryRef
+ DNSServiceOp *sdr;
+ };
+
+// Write len bytes. Return 0 on success, -1 on error
+static int write_all(dnssd_sock_t sd, char *buf, int len)
+ {
+ // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
+ //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
+ while (len)
+ {
+ ssize_t num_written = send(sd, buf, len, 0);
+ if (num_written < 0 || num_written > len)
+ {
+ // Should never happen. If it does, it indicates some OS bug,
+ // or that the mDNSResponder daemon crashed (which should never happen).
+ syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %d/%d %d %s", sd, num_written, len,
+ (num_written < 0) ? errno : 0,
+ (num_written < 0) ? strerror(errno) : "");
+ return -1;
+ }
+ buf += num_written;
+ len -= num_written;
+ }
+ return 0;
+ }
+
+// Read len bytes. Return 0 on success, -1 on error
+static int read_all(dnssd_sock_t sd, char *buf, int len)
+ {
+ // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
+ //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
-// <rdar://problem/4096913> Specifies how many times we'll try and connect to the
-// server.
-
-#define DNSSD_CLIENT_MAXTRIES 4
-
-#define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
-// error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
-// last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
-
-// general utility functions
-typedef struct _DNSServiceRef_t
- {
- dnssd_sock_t sockfd; // connected socket between client and daemon
- uint32_t op; // request_op_t or reply_op_t
- process_reply_callback process_reply;
- void *app_callback;
- void *app_context;
- uint32_t max_index; //largest assigned record index - 0 if no additl. recs registered
- } _DNSServiceRef_t;
-
-typedef struct _DNSRecordRef_t
- {
- void *app_context;
- DNSServiceRegisterRecordReply app_callback;
- DNSRecordRef recref;
- uint32_t record_index; // index is unique to the ServiceDiscoveryRef
- DNSServiceRef sdr;
- } _DNSRecordRef_t;
-
-// exported functions
-
-// write len bytes. return 0 on success, -1 on error
-static int my_write(dnssd_sock_t sd, char *buf, int len)
- {
- // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
- //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
- while (len)
- {
- ssize_t num_written = send(sd, buf, len, 0);
- if (num_written < 0 || num_written > len) return -1;
- buf += num_written;
- len -= num_written;
- }
- return 0;
- }
-
-// read len bytes. return 0 on success, -1 on error
-static int my_read(dnssd_sock_t sd, char *buf, int len)
- {
- // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
- //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
- while (len)
- {
- ssize_t num_read = recv(sd, buf, len, 0);
- if ((num_read == 0) || (num_read < 0) || (num_read > len)) return -1;
- buf += num_read;
- len -= num_read;
- }
- return 0;
- }
+ while (len)
+ {
+ ssize_t num_read = recv(sd, buf, len, 0);
+ if ((num_read == 0) || (num_read < 0) || (num_read > len))
+ {
+ // Should never happen. If it does, it indicates some OS bug,
+ // or that the mDNSResponder daemon crashed (which should never happen).
+ syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %d/%d %d %s", sd, num_read, len,
+ (num_read < 0) ? errno : 0,
+ (num_read < 0) ? strerror(errno) : "");
+ return -1;
+ }
+ buf += num_read;
+ len -= num_read;
+ }
+ return 0;
+ }
+
+// Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
+static int more_bytes(dnssd_sock_t sd)
+ {
+ struct timeval tv = { 0, 0 };
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(sd, &readfds);
+ return(select(sd+1, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv) > 0);
+ }
/* create_hdr
*
- * allocate and initialize an ipc message header. value of len should initially be the
- * length of the data, and is set to the value of the data plus the header. data_start
- * is set to point to the beginning of the data section. reuse_socket should be non-zero
- * for calls that can receive an immediate error return value on their primary socket.
+ * allocate and initialize an ipc message header. Value of len should initially be the
+ * length of the data, and is set to the value of the data plus the header. data_start
+ * is set to point to the beginning of the data section. SeparateReturnSocket should be
+ * non-zero for calls that can't receive an immediate error return value on their primary
+ * socket, and therefore require a separate return path for the error code result.
* if zero, the path to a control socket is appended at the beginning of the message buffer.
* data_start is set past this string.
*/
-
-static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int reuse_socket)
- {
- char *msg = NULL;
- ipc_msg_hdr *hdr;
- int datalen;
+static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
+ {
+ char *msg = NULL;
+ ipc_msg_hdr *hdr;
+ int datalen;
#if !defined(USE_TCP_LOOPBACK)
- char ctrl_path[256];
+ char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
#endif
- if (!reuse_socket)
- {
+ if (SeparateReturnSocket)
+ {
#if defined(USE_TCP_LOOPBACK)
- *len += 2; // Allocate space for two-byte port number
-#else
+ *len += 2; // Allocate space for two-byte port number
+#elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
struct timeval time;
- if (gettimeofday(&time, NULL) < 0) return NULL;
+ if (gettimeofday(&time, NULL) < 0)
+ { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", errno, strerror(errno)); return NULL; }
sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
(unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
- *len += strlen(ctrl_path) + 1;
+ *len += strlen(ctrl_path) + 1;
+#else
+ *len += 1; // Allocate space for single zero byte (empty C string)
#endif
- }
-
- datalen = (int) *len;
- *len += sizeof(ipc_msg_hdr);
-
- // write message to buffer
- msg = malloc(*len);
- if (!msg) return NULL;
-
- bzero(msg, *len);
- hdr = (void *)msg;
- hdr->datalen = datalen;
- hdr->version = VERSION;
- hdr->op = op;
- if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
- *data_start = msg + sizeof(ipc_msg_hdr);
+ }
+
+ datalen = (int) *len;
+ *len += sizeof(ipc_msg_hdr);
+
+ // Write message to buffer
+ msg = malloc(*len);
+ if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
+
+ bzero(msg, *len);
+ hdr = (ipc_msg_hdr *)msg;
+ hdr->version = VERSION;
+ hdr->datalen = datalen;
+ hdr->ipc_flags = 0;
+ hdr->op = op;
+ hdr->client_context = ref->uid;
+ hdr->reg_index = 0;
+ *data_start = msg + sizeof(ipc_msg_hdr);
#if defined(USE_TCP_LOOPBACK)
- // Put dummy data in for the port, since we don't know what
- // it is yet. The data will get filled in before we
- // send the message. This happens in deliver_request().
- if (!reuse_socket) put_short(0, data_start);
+ // Put dummy data in for the port, since we don't know what it is yet.
+ // The data will get filled in before we send the message. This happens in deliver_request().
+ if (SeparateReturnSocket) put_uint16(0, data_start);
#else
- if (!reuse_socket) put_string(ctrl_path, data_start);
+ if (SeparateReturnSocket) put_string(ctrl_path, data_start);
#endif
- return hdr;
- }
+ return hdr;
+ }
- // return a connected service ref (deallocate with DNSServiceRefDeallocate)
-static DNSServiceRef connect_to_server(void)
- {
- dnssd_sockaddr_t saddr;
- DNSServiceRef sdr;
+static void FreeDNSServiceOp(DNSServiceOp *x)
+ {
+ // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
+ // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
+ if ((x->sockfd ^ x->validator) != ValidatorBits)
+ syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
+ else
+ {
+ x->next = NULL;
+ x->primary = NULL;
+ x->sockfd = dnssd_InvalidSocket;
+ x->validator = 0xDDDDDDDD;
+ x->op = request_op_none;
+ x->max_index = 0;
+ x->logcounter = 0;
+ x->moreptr = NULL;
+ x->ProcessReply = NULL;
+ x->AppCallback = NULL;
+ x->AppContext = NULL;
+ free(x);
+ }
+ }
+
+// Return a connected service ref (deallocate with DNSServiceRefDeallocate)
+static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
+ {
+ #if APPLE_OSX_mDNSResponder
+ int NumTries = DNSSD_CLIENT_MAXTRIES;
+ #else
int NumTries = 0;
+ #endif
-#if defined(_WIN32)
+ dnssd_sockaddr_t saddr;
+ DNSServiceOp *sdr;
+
+ if (!ref) { syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (flags & kDNSServiceFlagsShareConnection)
+ {
+ if (!*ref)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
+ return kDNSServiceErr_BadParam;
+ }
+ if (!DNSServiceRefValid(*ref))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X",
+ (*ref), (*ref)->sockfd, (*ref)->validator);
+ *ref = NULL;
+ return kDNSServiceErr_BadReference;
+ }
+ }
+
+ #if defined(_WIN32)
if (!g_initWinsock)
{
WSADATA wsaData;
- DNSServiceErrorType err;
-
g_initWinsock = 1;
-
- err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
-
- if (err != 0) return NULL;
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
}
-
- // <rdar://problem/4096913> If the system service is disabled, we only want to try
- // to connect once
-
- if ( IsSystemServiceDisabled() )
+ // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
+ if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES;
+ #endif
+
+ sdr = malloc(sizeof(DNSServiceOp));
+ if (!sdr) { syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed"); *ref = NULL; return kDNSServiceErr_NoMemory; }
+ sdr->next = NULL;
+ sdr->primary = NULL;
+ sdr->sockfd = dnssd_InvalidSocket;
+ sdr->validator = sdr->sockfd ^ ValidatorBits;
+ sdr->op = op;
+ sdr->max_index = 0;
+ sdr->logcounter = 0;
+ sdr->moreptr = NULL;
+ sdr->uid.u32[0] = 0;
+ sdr->uid.u32[1] = 0;
+ sdr->ProcessReply = ProcessReply;
+ sdr->AppCallback = AppCallback;
+ sdr->AppContext = AppContext;
+
+ if (flags & kDNSServiceFlagsShareConnection)
{
- NumTries = DNSSD_CLIENT_MAXTRIES;
+ DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
+ while (*p) p = &(*p)->next;
+ *p = sdr;
+ sdr->primary = *ref; // Set our primary pointer
+ sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
+ sdr->validator = (*ref)->validator;
+ sdr->uid = (*ref)->uid;
+ if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
+ //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
}
-
-#endif
-
- sdr = malloc(sizeof(_DNSServiceRef_t));
- if (!sdr) return(NULL);
- sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
- if (sdr->sockfd == dnssd_InvalidSocket) { free(sdr); return NULL; }
-#if defined(USE_TCP_LOOPBACK)
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
- saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
-#else
- saddr.sun_family = AF_LOCAL;
- strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
-#endif
- while (1)
+ else
{
- int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
- if (!err) break; // If we succeeded, return sdr
- // If we failed, then it may be because the daemon is still launching.
- // This can happen for processes that launch early in the boot process, while the
- // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
- // If, after four seconds, we still can't connect to the daemon,
- // then we give up and return a failure code.
- if (++NumTries < DNSSD_CLIENT_MAXTRIES)
- sleep(1); // Sleep a bit, then try again
- else
+ *ref = NULL;
+ sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ sdr->validator = sdr->sockfd ^ ValidatorBits;
+ if (!dnssd_SocketValid(sdr->sockfd))
{
- dnssd_close(sdr->sockfd);
- sdr->sockfd = dnssd_InvalidSocket;
- free(sdr);
- return NULL;
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", errno, strerror(errno));
+ FreeDNSServiceOp(sdr);
+ return kDNSServiceErr_NoMemory;
}
+ #if defined(USE_TCP_LOOPBACK)
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+ saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
+ #else
+ saddr.sun_family = AF_LOCAL;
+ strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
+ #endif
+
+ while (1)
+ {
+ int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
+ if (!err) break; // If we succeeded, return sdr
+ // If we failed, then it may be because the daemon is still launching.
+ // This can happen for processes that launch early in the boot process, while the
+ // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
+ // If, after four seconds, we still can't connect to the daemon,
+ // then we give up and return a failure code.
+ if (++NumTries < DNSSD_CLIENT_MAXTRIES) sleep(1); // Sleep a bit, then try again
+ else { dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; }
+ }
+ //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
}
- return sdr;
+
+ *ref = sdr;
+ return kDNSServiceErr_NoError;
}
-static DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
- {
- ipc_msg_hdr *hdr = msg;
- uint32_t datalen = hdr->datalen;
- dnssd_sockaddr_t caddr, daddr; // (client and daemon address structs)
- char *data = (char *)msg + sizeof(ipc_msg_hdr);
- dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
- int ret;
- dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
- DNSServiceErrorType err = kDNSServiceErr_Unknown;
+static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
+ {
+ uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
+ #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
+ #endif
+ dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
+ DNSServiceErrorType err;
+ int MakeSeparateReturnSocket = 0;
+
+ // Note: need to check hdr->op, not sdr->op.
+ // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
+ // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
+ // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
+ if (sdr->primary ||
+ hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request)
+ MakeSeparateReturnSocket = 1;
+
+ if (!DNSServiceRefValid(sdr))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
+ return kDNSServiceErr_BadReference;
+ }
- if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
+ if (!hdr) { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr"); return kDNSServiceErr_Unknown; }
- if (!reuse_sd)
+ if (MakeSeparateReturnSocket)
{
- // setup temporary error socket
- if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) < 0)
- goto cleanup;
- bzero(&caddr, sizeof(caddr));
-
-#if defined(USE_TCP_LOOPBACK)
+ #if defined(USE_TCP_LOOPBACK)
{
union { uint16_t s; u_char b[2]; } port;
+ dnssd_sockaddr_t caddr;
+ dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
+ listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (!dnssd_SocketValid(listenfd)) goto cleanup;
+
caddr.sin_family = AF_INET;
caddr.sin_port = 0;
caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
- ret = bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr));
- if (ret < 0) goto cleanup;
+ if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) goto cleanup;
if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
listen(listenfd, 1);
port.s = caddr.sin_port;
- data[0] = port.b[0]; // don't switch the byte order, as the
- data[1] = port.b[1]; // daemon expects it in network byte order
+ data[0] = port.b[0]; // don't switch the byte order, as the
+ data[1] = port.b[1]; // daemon expects it in network byte order
}
-#else
+ #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
{
+ dnssd_sockaddr_t caddr;
mode_t mask = umask(0);
+ listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (!dnssd_SocketValid(listenfd)) goto cleanup;
+
caddr.sun_family = AF_LOCAL;
-#ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
- // determine whether sa_len is defined on a particular platform.
+ // According to Stevens (section 3.2), there is no portable way to
+ // determine whether sa_len is defined on a particular platform.
+ #ifndef NOT_HAVE_SA_LEN
caddr.sun_len = sizeof(struct sockaddr_un);
-#endif
+ #endif
strcpy(caddr.sun_path, data);
- ret = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
umask(mask);
- if (ret < 0) goto cleanup;
+ if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0) goto cleanup;
listen(listenfd, 1);
}
-#endif
+ #else
+ {
+ dnssd_sock_t sp[2];
+ //if (pipe(sp) < 0)
+ // syslog(LOG_WARNING, "dnssd_clientstub ERROR: pipe() failed errno %d (%s)", errno, strerror(errno));
+ if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ERROR: socketpair() failed errno %d (%s)", errno, strerror(errno));
+ else
+ {
+ errsd = sp[0]; // We'll read our four-byte error code from sp[0]
+ listenfd = sp[1]; // We'll send sp[1] to the daemon
+ }
+ }
+ #endif
}
+#if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // If we're going to make a separate error return socket, and pass it to the daemon
+ // using sendmsg, then we'll hold back one data byte to go with it.
+ // On some versions of Unix (including Leopard) sending a control message without
+ // any associated data does not work reliably -- e.g. one particular issue we ran
+ // into is that if the receiving program is in a kqueue loop waiting to be notified
+ // of the received message, it doesn't get woken up when the control message arrives.
+ if (MakeSeparateReturnSocket) datalen--;
+#endif
+
+ // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
ConvertHeaderBytes(hdr);
- if (my_write(sdr->sockfd, msg, datalen + sizeof(ipc_msg_hdr)) < 0)
- goto cleanup;
- free(msg);
- msg = NULL;
-
- if (reuse_sd) errsd = sdr->sockfd;
- else
- {
- len = sizeof(daddr);
- errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
- if (errsd < 0) goto cleanup;
- }
-
- if (my_read(errsd, (char*)&err, (int)sizeof(err)) < 0)
- err = kDNSServiceErr_Unknown;
- else
- err = ntohl(err);
+ //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %ld bytes", datalen + sizeof(ipc_msg_hdr));
+ //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
+#if TEST_SENDING_ONE_BYTE_AT_A_TIME
+ unsigned int i;
+ for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub writing %d", i);
+ if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0) goto cleanup;
+ usleep(10000);
+ }
+#else
+ if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) goto cleanup;
+#endif
+
+ if (!MakeSeparateReturnSocket) errsd = sdr->sockfd;
+ else
+ {
+#if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // At this point we may block in accept for a few milliseconds waiting for the daemon to connect back to us,
+ // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
+ dnssd_sockaddr_t daddr;
+ dnssd_socklen_t len = sizeof(daddr);
+ errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
+ if (!dnssd_SocketValid(errsd)) goto cleanup;
+#else
+ struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char cbuf[sizeof(struct cmsghdr) + sizeof(dnssd_sock_t)];
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
+ msg.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = sizeof(cbuf);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
+#if TEST_KQUEUE_CONTROL_MESSAGE_BUG
+ sleep(1);
+#endif
+ if (sendmsg(sdr->sockfd, &msg, 0) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
+ errsd, listenfd, errno, strerror(errno));
+#endif
+ }
+
+ // At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code,
+ // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
+ if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
+ err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
+ else
+ err = ntohl(err);
+
+ //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
cleanup:
- if (!reuse_sd && listenfd > 0) dnssd_close(listenfd);
- if (!reuse_sd && errsd > 0) dnssd_close(errsd);
-#if !defined(USE_TCP_LOOPBACK)
- if (!reuse_sd && data) unlink(data);
+ if (MakeSeparateReturnSocket)
+ {
+ if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
+ if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
+#if defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
+ if (unlink(data) != 0)
+ syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, errno, strerror(errno));
+ // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
#endif
- if (msg) free(msg);
- return err;
- }
+ }
+ free(hdr);
+ return err;
+ }
int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
- {
- if (!sdRef) return -1;
- return (int) sdRef->sockfd;
- }
+ {
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
+ sdRef, sdRef->sockfd, sdRef->validator);
+ return dnssd_InvalidSocket;
+ }
-// handle reply from server, calling application client callback. If there is no reply
+ if (sdRef->primary)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
+ return dnssd_InvalidSocket;
+ }
+
+ return (int) sdRef->sockfd;
+ }
+
+// Handle reply from server, calling application client callback. If there is no reply
// from the daemon on the socket contained in sdRef, the call will block.
DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
- {
- ipc_msg_hdr hdr;
- char *data;
+ {
+ int morebytes = 0;
- if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply)
- return kDNSServiceErr_BadReference;
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
- if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0)
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (sdRef->primary)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (!sdRef->ProcessReply)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
+ return kDNSServiceErr_BadReference;
+ }
+
+ do
+ {
+ CallbackHeader cbh;
+ char *data;
+
// return NoError on EWOULDBLOCK. This will handle the case
- // where a non-blocking socket is told there is data, but
- // it was a false positive.
- return (dnssd_errno() == dnssd_EWOULDBLOCK) ? kDNSServiceErr_NoError : kDNSServiceErr_Unknown;
- ConvertHeaderBytes(&hdr);
- if (hdr.version != VERSION)
- return kDNSServiceErr_Incompatible;
- data = malloc(hdr.datalen);
- if (!data) return kDNSServiceErr_NoMemory;
- if (my_read(sdRef->sockfd, data, hdr.datalen) < 0)
- return kDNSServiceErr_Unknown;
- sdRef->process_reply(sdRef, &hdr, data);
- free(data);
- return kDNSServiceErr_NoError;
- }
+ // where a non-blocking socket is told there is data, but it was a false positive.
+ // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
+ if (read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr)) < 0)
+ {
+ if (dnssd_errno() != dnssd_EWOULDBLOCK)
+ {
+ sdRef->ProcessReply = NULL;
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ else
+ {
+ if (morebytes && sdRef->logcounter < 100)
+ {
+ sdRef->logcounter++;
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
+ }
+ return kDNSServiceErr_NoError;
+ }
+ }
+
+ ConvertHeaderBytes(&cbh.ipc_hdr);
+ if (cbh.ipc_hdr.version != VERSION)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
+ sdRef->ProcessReply = NULL;
+ return kDNSServiceErr_Incompatible;
+ }
+
+ data = malloc(cbh.ipc_hdr.datalen);
+ if (!data) return kDNSServiceErr_NoMemory;
+ if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
+ {
+ free(data);
+ sdRef->ProcessReply = NULL;
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ else
+ {
+ char *ptr = data;
+ cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
+ cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
+ cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
+
+ // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
+ // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
+ // then that routine will clear morebytes for us, and cause us to exit our loop.
+ morebytes = more_bytes(sdRef->sockfd);
+ if (morebytes)
+ {
+ cbh.cb_flags |= kDNSServiceFlagsMoreComing;
+ sdRef->moreptr = &morebytes;
+ }
+ if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
+ // Careful code here:
+ // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
+ // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
+ // dangling pointer pointing to a long-gone stack variable.
+ // If morebytes is zero, then one of two thing happened:
+ // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
+ // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
+ // so we MUST NOT try to dereference our stale sdRef pointer.
+ if (morebytes) sdRef->moreptr = NULL;
+ }
+ free(data);
+ } while (morebytes);
+
+ return kDNSServiceErr_NoError;
+ }
void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
- {
- if (!sdRef) return;
- if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd);
- free(sdRef);
- }
-
-static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
- {
- DNSServiceFlags flags;
- char fullname[kDNSServiceMaxDomainName];
- char target[kDNSServiceMaxDomainName];
- uint16_t txtlen;
- union { uint16_t s; u_char b[2]; } port;
- uint32_t ifi;
- DNSServiceErrorType err;
- char *txtrecord;
- int str_error = 0;
- (void)hdr; //unused
-
- flags = get_flags(&data);
- ifi = get_long(&data);
- err = get_error_code(&data);
- if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
- if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
- port.b[0] = *data++;
- port.b[1] = *data++;
- txtlen = get_short(&data);
- txtrecord = get_rdata(&data, txtlen);
-
- if (!err && str_error) err = kDNSServiceErr_Unknown;
- ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port.s, txtlen, txtrecord, sdr->app_context);
- }
+ {
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
+
+ if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return;
+ }
+
+ // If we're in the middle of a DNSServiceProcessResult() invocation for this DNSServiceRef, clear its morebytes flag to break it out of its while loop
+ if (sdRef->moreptr) *(sdRef->moreptr) = 0;
+
+ if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
+ {
+ DNSServiceOp **p = &sdRef->primary->next;
+ while (*p && *p != sdRef) p = &(*p)->next;
+ if (*p)
+ {
+ char *ptr;
+ size_t len = 0;
+ ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
+ ConvertHeaderBytes(hdr);
+ write_all(sdRef->sockfd, (char *)hdr, len);
+ free(hdr);
+ *p = sdRef->next;
+ FreeDNSServiceOp(sdRef);
+ }
+ }
+ else // else, make sure to terminate all subordinates as well
+ {
+ dnssd_close(sdRef->sockfd);
+ while (sdRef)
+ {
+ DNSServiceOp *p = sdRef;
+ sdRef = sdRef->next;
+ FreeDNSServiceOp(p);
+ }
+ }
+ }
+
+DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
+ {
+ char *ptr;
+ size_t len = strlen(property) + 1;
+ ipc_msg_hdr *hdr;
+ DNSServiceOp *tmp;
+ uint32_t actualsize;
+
+ DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_string(property, &ptr);
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
+ { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+
+ actualsize = ntohl(actualsize);
+ if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
+ { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ DNSServiceRefDeallocate(tmp);
+
+ // Swap version result back to local process byte order
+ if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
+ *(uint32_t*)result = ntohl(*(uint32_t*)result);
+
+ *size = actualsize;
+ return kDNSServiceErr_NoError;
+ }
+
+static void handle_resolve_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+ {
+ char fullname[kDNSServiceMaxDomainName];
+ char target[kDNSServiceMaxDomainName];
+ uint16_t txtlen;
+ union { uint16_t s; u_char b[2]; } port;
+ unsigned char *txtrecord;
+
+ get_string(&data, end, fullname, kDNSServiceMaxDomainName);
+ get_string(&data, end, target, kDNSServiceMaxDomainName);
+ if (data + 2 > end) data = NULL;
+ else
+ {
+ port.b[0] = *data++;
+ port.b[1] = *data++;
+ }
+ txtlen = get_uint16(&data, end);
+ txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
+
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
+ else ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
DNSServiceErrorType DNSSD_API DNSServiceResolve
- (
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name,
- const char *regtype,
- const char *domain,
- DNSServiceResolveReply callBack,
- void *context
- )
- {
- char *msg = NULL, *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceRef sdr;
- DNSServiceErrorType err;
-
- if (!sdRef) return kDNSServiceErr_BadParam;
- *sdRef = NULL;
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ DNSServiceResolveReply callBack,
+ void *context
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
- // calculate total message length
- len = sizeof(flags);
- len += sizeof(interfaceIndex);
- len += strlen(name) + 1;
- len += strlen(regtype) + 1;
- len += strlen(domain) + 1;
-
- hdr = create_hdr(resolve_request, &len, &ptr, 1);
- if (!hdr) goto error;
- msg = (void *)hdr;
-
- put_flags(flags, &ptr);
- put_long(interfaceIndex, &ptr);
- put_string(name, &ptr);
- put_string(regtype, &ptr);
- put_string(domain, &ptr);
-
- sdr = connect_to_server();
- if (!sdr) goto error;
- err = deliver_request(msg, sdr, 1);
- if (err)
- {
- DNSServiceRefDeallocate(sdr);
- return err;
- }
- sdr->op = resolve_request;
- sdr->process_reply = handle_resolve_response;
- sdr->app_callback = callBack;
- sdr->app_context = context;
- *sdRef = sdr;
-
- return err;
-
-error:
- if (msg) free(msg);
- if (*sdRef) { free(*sdRef); *sdRef = NULL; }
- return kDNSServiceErr_Unknown;
- }
-
-static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
- {
- DNSServiceFlags flags;
- uint32_t interfaceIndex, ttl;
- DNSServiceErrorType errorCode;
- char name[kDNSServiceMaxDomainName];
- uint16_t rrtype, rrclass, rdlen;
- char *rdata;
- int str_error = 0;
- (void)hdr;//Unused
-
- flags = get_flags(&data);
- interfaceIndex = get_long(&data);
- errorCode = get_error_code(&data);
- if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
- rrtype = get_short(&data);
- rrclass = get_short(&data);
- rdlen = get_short(&data);
- rdata = get_rdata(&data, rdlen);
- ttl = get_long(&data);
-
- if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
- ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
- rdlen, rdata, ttl, sdr->app_context);
- return;
- }
+ err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += strlen(name) + 1;
+ len += strlen(regtype) + 1;
+ len += strlen(domain) + 1;
+
+ hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+ }
+
+static void handle_query_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+ {
+ uint32_t ttl;
+ char name[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ char *rdata;
+
+ get_string(&data, end, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ ttl = get_uint32(&data, end);
+
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
+ else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name,
- uint16_t rrtype,
- uint16_t rrclass,
- DNSServiceQueryRecordReply callBack,
- void *context
- )
- {
- char *msg = NULL, *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceRef sdr;
- DNSServiceErrorType err;
-
- if (!sdRef) return kDNSServiceErr_BadParam;
- *sdRef = NULL;
-
- if (!name) name = "\0";
-
- // calculate total message length
- len = sizeof(flags);
- len += sizeof(uint32_t); //interfaceIndex
- len += strlen(name) + 1;
- len += 2 * sizeof(uint16_t); // rrtype, rrclass
-
- hdr = create_hdr(query_request, &len, &ptr, 1);
- if (!hdr) goto error;
- msg = (void *)hdr;
-
- put_flags(flags, &ptr);
- put_long(interfaceIndex, &ptr);
- put_string(name, &ptr);
- put_short(rrtype, &ptr);
- put_short(rrclass, &ptr);
-
- sdr = connect_to_server();
- if (!sdr) goto error;
- err = deliver_request(msg, sdr, 1);
- if (err)
- {
- DNSServiceRefDeallocate(sdr);
- return err;
- }
-
- sdr->op = query_request;
- sdr->process_reply = handle_query_response;
- sdr->app_callback = callBack;
- sdr->app_context = context;
- *sdRef = sdr;
- return err;
-
-error:
- if (msg) free(msg);
- if (*sdRef) { free(*sdRef); *sdRef = NULL; }
- return kDNSServiceErr_Unknown;
- }
-
-static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
- {
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- DNSServiceErrorType errorCode;
- char replyName[256], replyType[kDNSServiceMaxDomainName],
- replyDomain[kDNSServiceMaxDomainName];
- int str_error = 0;
- (void)hdr;//Unused
-
- flags = get_flags(&data);
- interfaceIndex = get_long(&data);
- errorCode = get_error_code(&data);
- if (get_string(&data, replyName, 256) < 0) str_error = 1;
- if (get_string(&data, replyType, kDNSServiceMaxDomainName) < 0) str_error = 1;
- if (get_string(&data, replyDomain, kDNSServiceMaxDomainName) < 0) str_error = 1;
- if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
- ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
- }
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ DNSServiceQueryRecordReply callBack,
+ void *context
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ if (!name) name = "\0";
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += strlen(name) + 1;
+ len += 2 * sizeof(uint16_t); // rrtype, rrclass
+
+ hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+ }
+
+static void handle_addrinfo_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+ {
+ uint32_t ttl;
+ char hostname[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ char *rdata;
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ struct sockaddr * sa = NULL;
+
+ get_string(&data, end, hostname, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ ttl = get_uint32(&data, end);
+
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
+ else
+ {
+ if (rrtype == kDNSServiceType_A)
+ {
+ sa = (struct sockaddr *)&sa4;
+ bzero(&sa4, sizeof(sa4));
+ #ifndef NOT_HAVE_SA_LEN
+ sa->sa_len = sizeof(struct sockaddr_in);
+ #endif
+ sa->sa_family = AF_INET;
+ if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
+ }
+ else if (rrtype == kDNSServiceType_AAAA)
+ {
+ sa = (struct sockaddr *)&sa6;
+ bzero(&sa6, sizeof(sa6));
+ #ifndef NOT_HAVE_SA_LEN
+ sa->sa_len = sizeof(struct sockaddr_in6);
+ #endif
+ sa->sa_family = AF_INET6;
+ if (!cbh->cb_err) memcpy(&sa6.sin6_addr, rdata, rdlen);
+ }
+ ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
+ }
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ uint32_t protocol,
+ const char *hostname,
+ DNSServiceGetAddrInfoReply callBack,
+ void *context /* may be NULL */
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if (!hostname) return kDNSServiceErr_BadParam;
+
+ err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += sizeof(uint32_t); // protocol
+ len += strlen(hostname) + 1;
+
+ hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_uint32(protocol, &ptr);
+ put_string(hostname, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+ }
+
+static void handle_browse_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+ {
+ char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
+ get_string(&data, end, replyName, 256);
+ get_string(&data, end, replyType, kDNSServiceMaxDomainName);
+ get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
+ else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
DNSServiceErrorType DNSSD_API DNSServiceBrowse
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *regtype,
- const char *domain,
- DNSServiceBrowseReply callBack,
- void *context
- )
- {
- char *msg = NULL, *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceRef sdr;
- DNSServiceErrorType err;
-
- if (!sdRef) return kDNSServiceErr_BadParam;
- *sdRef = NULL;
-
- if (!domain) domain = "";
-
- len = sizeof(flags);
- len += sizeof(interfaceIndex);
- len += strlen(regtype) + 1;
- len += strlen(domain) + 1;
-
- hdr = create_hdr(browse_request, &len, &ptr, 1);
- if (!hdr) goto error;
- msg = (char *)hdr;
- put_flags(flags, &ptr);
- put_long(interfaceIndex, &ptr);
- put_string(regtype, &ptr);
- put_string(domain, &ptr);
-
- sdr = connect_to_server();
- if (!sdr) goto error;
- err = deliver_request(msg, sdr, 1);
- if (err)
- {
- DNSServiceRefDeallocate(sdr);
- return err;
- }
- sdr->op = browse_request;
- sdr->process_reply = handle_browse_response;
- sdr->app_callback = callBack;
- sdr->app_context = context;
- *sdRef = sdr;
- return err;
-
-error:
- if (msg) free(msg);
- if (*sdRef) { free(*sdRef); *sdRef = NULL; }
- return kDNSServiceErr_Unknown;
- }
-
-DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
-(
- DNSServiceFlags flags,
- const char *domain
- )
- {
- DNSServiceRef sdr;
- DNSServiceErrorType err;
- char *ptr = NULL;
- size_t len = sizeof(flags) + strlen(domain) + 1;
- ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1);
-
- if (!hdr) return kDNSServiceErr_Unknown;
- put_flags(flags, &ptr);
- put_string(domain, &ptr);
-
- sdr = connect_to_server();
- if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; }
- err = deliver_request((char *)hdr, sdr, 1); // deliver_request frees the message for us
- DNSServiceRefDeallocate(sdr);
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *regtype,
+ const char *domain,
+ DNSServiceBrowseReply callBack,
+ void *context
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ if (!domain) domain = "";
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += strlen(regtype) + 1;
+ len += strlen(domain) + 1;
+
+ hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
return err;
- }
-
-
-static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
- {
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- DNSServiceErrorType errorCode;
- char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
- int str_error = 0;
- (void)hdr;//Unused
-
- flags = get_flags(&data);
- interfaceIndex = get_long(&data);
- errorCode = get_error_code(&data);
- if (get_string(&data, name, 256) < 0) str_error = 1;
- if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1;
- if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
- if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
- ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
- }
+ }
+
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
+ {
+ DNSServiceOp *tmp;
+ char *ptr;
+ size_t len = sizeof(flags) + strlen(domain) + 1;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_string(domain, &ptr);
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ DNSServiceRefDeallocate(tmp);
+ return err;
+ }
+
+static void handle_regservice_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+ {
+ char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
+ get_string(&data, end, name, 256);
+ get_string(&data, end, regtype, kDNSServiceMaxDomainName);
+ get_string(&data, end, domain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
+ else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
DNSServiceErrorType DNSSD_API DNSServiceRegister
- (
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name,
- const char *regtype,
- const char *domain,
- const char *host,
- uint16_t PortInNetworkByteOrder,
- uint16_t txtLen,
- const void *txtRecord,
- DNSServiceRegisterReply callBack,
- void *context
- )
- {
- char *msg = NULL, *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceRef sdr;
- DNSServiceErrorType err;
- union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
-
- if (!sdRef) return kDNSServiceErr_BadParam;
- *sdRef = NULL;
-
- if (!name) name = "";
- if (!regtype) return kDNSServiceErr_BadParam;
- if (!domain) domain = "";
- if (!host) host = "";
- if (!txtRecord) txtRecord = (void*)"";
-
- // auto-name must also have auto-rename
- if (!name[0] && (flags & kDNSServiceFlagsNoAutoRename))
- return kDNSServiceErr_BadParam;
-
- // no callback must have auto-name
- if (!callBack && name[0]) return kDNSServiceErr_BadParam;
-
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t); // interfaceIndex
- len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
- len += 2 * sizeof(uint16_t); // port, txtLen
- len += txtLen;
-
- hdr = create_hdr(reg_service_request, &len, &ptr, 1);
- if (!hdr) goto error;
- if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
- msg = (char *)hdr;
- put_flags(flags, &ptr);
- put_long(interfaceIndex, &ptr);
- put_string(name, &ptr);
- put_string(regtype, &ptr);
- put_string(domain, &ptr);
- put_string(host, &ptr);
- *ptr++ = port.b[0];
- *ptr++ = port.b[1];
- put_short(txtLen, &ptr);
- put_rdata(txtLen, txtRecord, &ptr);
-
- sdr = connect_to_server();
- if (!sdr) goto error;
- err = deliver_request(msg, sdr, 1);
- if (err)
- {
- DNSServiceRefDeallocate(sdr);
- return err;
- }
-
- sdr->op = reg_service_request;
- sdr->process_reply = callBack ? handle_regservice_response : NULL;
- sdr->app_callback = callBack;
- sdr->app_context = context;
- *sdRef = sdr;
-
- return err;
-
-error:
- if (msg) free(msg);
- if (*sdRef) { free(*sdRef); *sdRef = NULL; }
- return kDNSServiceErr_Unknown;
- }
-
-static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
- {
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- DNSServiceErrorType err;
- char domain[kDNSServiceMaxDomainName];
- int str_error = 0;
- (void)hdr;//Unused
-
- flags = get_flags(&data);
- interfaceIndex = get_long(&data);
- err = get_error_code(&data);
- if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
- if (!err && str_error) err = kDNSServiceErr_Unknown;
- ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
- }
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ const char *host,
+ uint16_t PortInNetworkByteOrder,
+ uint16_t txtLen,
+ const void *txtRecord,
+ DNSServiceRegisterReply callBack,
+ void *context
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+ union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
+
+ if (!name) name = "";
+ if (!regtype) return kDNSServiceErr_BadParam;
+ if (!domain) domain = "";
+ if (!host) host = "";
+ if (!txtRecord) txtRecord = (void*)"";
+
+ // No callback must have auto-rename
+ if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
+
+ err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
+ len += 2 * sizeof(uint16_t); // port, txtLen
+ len += txtLen;
+
+ hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+ if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+ put_string(host, &ptr);
+ *ptr++ = port.b[0];
+ *ptr++ = port.b[1];
+ put_uint16(txtLen, &ptr);
+ put_rdata(txtLen, txtRecord, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+ }
+
+static void handle_enumeration_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+ {
+ char domain[kDNSServiceMaxDomainName];
+ get_string(&data, end, domain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
+ else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceDomainEnumReply callBack,
- void *context
- )
- {
- char *msg = NULL, *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceRef sdr;
- DNSServiceErrorType err;
- int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
- int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
- if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
-
- if (!sdRef) return kDNSServiceErr_BadParam;
- *sdRef = NULL;
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceDomainEnumReply callBack,
+ void *context
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
+ int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
+ if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+ err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t);
-
- hdr = create_hdr(enumeration_request, &len, &ptr, 1);
- if (!hdr) goto error;
- msg = (void *)hdr;
-
- put_flags(flags, &ptr);
- put_long(interfaceIndex, &ptr);
-
- sdr = connect_to_server();
- if (!sdr) goto error;
- err = deliver_request(msg, sdr, 1);
- if (err)
- {
- DNSServiceRefDeallocate(sdr);
- return err;
- }
-
- sdr->op = enumeration_request;
- sdr->process_reply = handle_enumeration_response;
- sdr->app_callback = callBack;
- sdr->app_context = context;
- *sdRef = sdr;
- return err;
-
-error:
- if (msg) free(msg);
- if (*sdRef) { free(*sdRef); *sdRef = NULL; }
- return kDNSServiceErr_Unknown;
- }
-
-static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
- {
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- DNSServiceErrorType errorCode;
- DNSRecordRef rref = hdr->client_context.context;
-
- if (sdr->op != connection)
- {
- rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
- return;
- }
- flags = get_flags(&data);
- interfaceIndex = get_long(&data);
- errorCode = get_error_code(&data);
-
- rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
- }
+ len += sizeof(uint32_t);
+
+ hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+ }
+
+static void ConnectionResponse(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+ {
+ DNSRecordRef rref = cbh->ipc_hdr.client_context.context;
+ (void)data; // Unused
+
+ //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
+ if (cbh->ipc_hdr.op != reg_record_reply_op)
+ {
+ // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
+ // to find the one this response is intended for, and then call through to its ProcessReply handler
+ while (sdr && (sdr->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || sdr->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
+ sdr = sdr->next;
+ // NOTE: We may sometimes not find a matching DNSServiceOp, in the case where the client has
+ // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
+ if (sdr && sdr->ProcessReply) sdr->ProcessReply(sdr, cbh, data, end);
+ // WARNING: Don't touch sdr after this -- client may have called DNSServiceRefDeallocate
+ return;
+ }
+
+ if (sdr->op == connection_request)
+ rref->AppCallback(rref->sdr, rref, cbh->cb_flags, cbh->cb_err, rref->AppContext);
+ else
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub handle_regrecord_response: sdr->op != connection_request");
+ rref->AppCallback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->AppContext);
+ }
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
- {
- if (!sdRef) return kDNSServiceErr_BadParam;
- *sdRef = connect_to_server();
- if (!*sdRef)
- return kDNSServiceErr_Unknown;
- (*sdRef)->op = connection;
- (*sdRef)->process_reply = handle_regrecord_response;
- return 0;
- }
+ {
+ char *ptr;
+ size_t len = 0;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+ }
DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef *RecordRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl,
- DNSServiceRegisterRecordReply callBack,
- void *context
- )
- {
- char *msg = NULL, *ptr;
- size_t len;
- ipc_msg_hdr *hdr = NULL;
- DNSServiceRef tmp = NULL;
- DNSRecordRef rref = NULL;
- int f1 = (flags & kDNSServiceFlagsShared) != 0;
- int f2 = (flags & kDNSServiceFlagsUnique) != 0;
- if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
-
- if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
- return kDNSServiceErr_BadReference;
- *RecordRef = NULL;
+ (
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ DNSServiceRegisterRecordReply callBack,
+ void *context
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr = NULL;
+ DNSRecordRef rref = NULL;
+ int f1 = (flags & kDNSServiceFlagsShared) != 0;
+ int f2 = (flags & kDNSServiceFlagsUnique) != 0;
+ if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (sdRef->op != connection_request)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
+ return kDNSServiceErr_BadReference;
+ }
+
+ *RecordRef = NULL;
len = sizeof(DNSServiceFlags);
- len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
- len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
- len += strlen(fullname) + 1;
- len += rdlen;
-
- hdr = create_hdr(reg_record_request, &len, &ptr, 0);
- if (!hdr) goto error;
- msg = (char *)hdr;
- put_flags(flags, &ptr);
- put_long(interfaceIndex, &ptr);
- put_string(fullname, &ptr);
- put_short(rrtype, &ptr);
- put_short(rrclass, &ptr);
- put_short(rdlen, &ptr);
- put_rdata(rdlen, rdata, &ptr);
- put_long(ttl, &ptr);
-
- rref = malloc(sizeof(_DNSRecordRef_t));
- if (!rref) goto error;
- rref->app_context = context;
- rref->app_callback = callBack;
- rref->record_index = sdRef->max_index++;
- rref->sdr = sdRef;
- *RecordRef = rref;
- hdr->client_context.context = rref;
- hdr->reg_index = rref->record_index;
-
- return deliver_request(msg, sdRef, 0);
-
-error:
- if (rref) free(rref);
- if (tmp) free(tmp);
- if (hdr) free(hdr);
- return kDNSServiceErr_Unknown;
- }
-
-//sdRef returned by DNSServiceRegister()
+ len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
+ len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
+ len += strlen(fullname) + 1;
+ len += rdlen;
+
+ hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(fullname, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+
+ rref = malloc(sizeof(DNSRecord));
+ if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
+ rref->AppContext = context;
+ rref->AppCallback = callBack;
+ rref->record_index = sdRef->max_index++;
+ rref->sdr = sdRef;
+ *RecordRef = rref;
+ hdr->client_context.context = rref;
+ hdr->reg_index = rref->record_index;
+
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+ }
+
+// sdRef returned by DNSServiceRegister()
DNSServiceErrorType DNSSD_API DNSServiceAddRecord
- (
- DNSServiceRef sdRef,
- DNSRecordRef *RecordRef,
- DNSServiceFlags flags,
- uint16_t rrtype,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl
- )
- {
- ipc_msg_hdr *hdr;
- size_t len = 0;
- char *ptr;
- DNSRecordRef rref;
-
- if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
- return kDNSServiceErr_BadReference;
- *RecordRef = NULL;
-
- len += 2 * sizeof(uint16_t); //rrtype, rdlen
- len += rdlen;
- len += sizeof(uint32_t);
- len += sizeof(DNSServiceFlags);
-
- hdr = create_hdr(add_record_request, &len, &ptr, 0);
- if (!hdr) return kDNSServiceErr_Unknown;
- put_flags(flags, &ptr);
- put_short(rrtype, &ptr);
- put_short(rdlen, &ptr);
- put_rdata(rdlen, rdata, &ptr);
- put_long(ttl, &ptr);
-
- rref = malloc(sizeof(_DNSRecordRef_t));
- if (!rref) goto error;
- rref->app_context = NULL;
- rref->app_callback = NULL;
- rref->record_index = sdRef->max_index++;
- rref->sdr = sdRef;
- *RecordRef = rref;
- hdr->client_context.context = rref;
- hdr->reg_index = rref->record_index;
- return deliver_request((char *)hdr, sdRef, 0);
-
-error:
- if (hdr) free(hdr);
- if (rref) free(rref);
- if (*RecordRef) *RecordRef = NULL;
- return kDNSServiceErr_Unknown;
-}
-
-//DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
+ (
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint16_t rrtype,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+ )
+ {
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+ DNSRecordRef rref;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+ if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
+ if (sdRef->op != reg_service_request)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ *RecordRef = NULL;
+
+ len += 2 * sizeof(uint16_t); // rrtype, rdlen
+ len += rdlen;
+ len += sizeof(uint32_t);
+ len += sizeof(DNSServiceFlags);
+
+ hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ put_flags(flags, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+
+ rref = malloc(sizeof(DNSRecord));
+ if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
+ rref->AppContext = NULL;
+ rref->AppCallback = NULL;
+ rref->record_index = sdRef->max_index++;
+ rref->sdr = sdRef;
+ *RecordRef = rref;
+ hdr->client_context.context = rref;
+ hdr->reg_index = rref->record_index;
+
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+ }
+
+// DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
- (
- DNSServiceRef sdRef,
- DNSRecordRef RecordRef,
- DNSServiceFlags flags,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl
- )
- {
- ipc_msg_hdr *hdr;
- size_t len = 0;
- char *ptr;
-
- if (!sdRef) return kDNSServiceErr_BadReference;
-
- len += sizeof(uint16_t);
- len += rdlen;
- len += sizeof(uint32_t);
- len += sizeof(DNSServiceFlags);
-
- hdr = create_hdr(update_record_request, &len, &ptr, 0);
- if (!hdr) return kDNSServiceErr_Unknown;
- hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
- put_flags(flags, &ptr);
- put_short(rdlen, &ptr);
- put_rdata(rdlen, rdata, &ptr);
- put_long(ttl, &ptr);
- return deliver_request((char *)hdr, sdRef, 0);
- }
+ (
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+ )
+ {
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ // Note: RecordRef is allowed to be NULL
+
+ len += sizeof(uint16_t);
+ len += rdlen;
+ len += sizeof(uint32_t);
+ len += sizeof(DNSServiceFlags);
+
+ hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
+ put_flags(flags, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+ }
DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef RecordRef,
- DNSServiceFlags flags
- )
- {
- ipc_msg_hdr *hdr;
- size_t len = 0;
- char *ptr;
- DNSServiceErrorType err;
-
- if (!sdRef || !RecordRef || !sdRef->max_index)
- return kDNSServiceErr_BadReference;
-
- len += sizeof(flags);
- hdr = create_hdr(remove_record_request, &len, &ptr, 0);
- if (!hdr) return kDNSServiceErr_Unknown;
- hdr->reg_index = RecordRef->record_index;
- put_flags(flags, &ptr);
- err = deliver_request((char *)hdr, sdRef, 0);
- if (!err) free(RecordRef);
- return err;
- }
-
-void DNSSD_API DNSServiceReconfirmRecord
-(
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata
- )
- {
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceRef tmp;
-
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t);
- len += strlen(fullname) + 1;
- len += 3 * sizeof(uint16_t);
- len += rdlen;
- tmp = connect_to_server();
- if (!tmp) return;
- hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
- if (!hdr) return;
-
- put_flags(flags, &ptr);
- put_long(interfaceIndex, &ptr);
- put_string(fullname, &ptr);
- put_short(rrtype, &ptr);
- put_short(rrclass, &ptr);
- put_short(rdlen, &ptr);
- put_rdata(rdlen, rdata, &ptr);
- ConvertHeaderBytes(hdr);
- my_write(tmp->sockfd, (char *)hdr, (int) len);
- free(hdr);
- DNSServiceRefDeallocate(tmp);
- }
+ (
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags
+ )
+ {
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+ DNSServiceErrorType err;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+ if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
+ if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+ len += sizeof(flags);
+ hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ hdr->reg_index = RecordRef->record_index;
+ put_flags(flags, &ptr);
+ err = deliver_request(hdr, sdRef); // Will free hdr for us
+ if (!err) free(RecordRef);
+ return err;
+ }
+
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
+ (
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceOp *tmp;
+
+ DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t);
+ len += strlen(fullname) + 1;
+ len += 3 * sizeof(uint16_t);
+ len += rdlen;
+ hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(fullname, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ DNSServiceRefDeallocate(tmp);
+ return err;
+ }
+
+static void handle_port_mapping_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
+ {
+ union { uint32_t l; u_char b[4]; } addr;
+ uint8_t protocol = 0;
+ union { uint16_t s; u_char b[2]; } privatePort;
+ union { uint16_t s; u_char b[2]; } publicPort;
+ uint32_t ttl = 0;
+
+ if (data + 13 > end) data = NULL;
+ else
+ {
+ addr .b[0] = *data++;
+ addr .b[1] = *data++;
+ addr .b[2] = *data++;
+ addr .b[3] = *data++;
+ protocol = *data++;
+ privatePort.b[0] = *data++;
+ privatePort.b[1] = *data++;
+ publicPort .b[0] = *data++;
+ publicPort .b[1] = *data++;
+ ttl = get_uint32(&data, end);
+ }
+
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
+ else ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, privatePort.s, publicPort.s, ttl, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
+
+DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ uint32_t protocol, /* TCP and/or UDP */
+ uint16_t privatePortInNetworkByteOrder,
+ uint16_t publicPortInNetworkByteOrder,
+ uint32_t ttl, /* time to live in seconds */
+ DNSServiceNATPortMappingReply callBack,
+ void *context /* may be NULL */
+ )
+ {
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ union { uint16_t s; u_char b[2]; } privatePort = { privatePortInNetworkByteOrder };
+ union { uint16_t s; u_char b[2]; } publicPort = { publicPortInNetworkByteOrder };
+
+ DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += sizeof(protocol);
+ len += sizeof(privatePort);
+ len += sizeof(publicPort);
+ len += sizeof(ttl);
+
+ hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_uint32(protocol, &ptr);
+ *ptr++ = privatePort.b[0];
+ *ptr++ = privatePort.b[1];
+ *ptr++ = publicPort .b[0];
+ *ptr++ = publicPort .b[1];
+ put_uint32(ttl, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+ }
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log: dnssd_ipc.c,v $
+Revision 1.20 2007/07/23 22:12:53 cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
+
+Revision 1.19 2007/05/16 01:06:52 cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
+
+Revision 1.18 2007/03/21 19:01:57 cheshire
+<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
+
+Revision 1.17 2006/10/27 00:38:22 cheshire
+Strip accidental trailing whitespace from lines
+
+Revision 1.16 2006/08/14 23:05:53 cheshire
+Added "tab-width" emacs header line
+
Revision 1.15 2005/01/27 22:57:56 cheshire
Fix compile errors on gcc4
#include "dnssd_ipc.h"
-void put_long(const uint32_t l, char **ptr)
+void put_uint32(const uint32_t l, char **ptr)
{
(*ptr)[0] = (char)((l >> 24) & 0xFF);
(*ptr)[1] = (char)((l >> 16) & 0xFF);
*ptr += sizeof(uint32_t);
}
-uint32_t get_long(char **ptr)
+uint32_t get_uint32(char **ptr, char *end)
{
- uint8_t *p = (uint8_t*) *ptr;
- *ptr += sizeof(uint32_t);
- return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
+ if (!*ptr || *ptr + sizeof(uint32_t) > end)
+ {
+ *ptr = NULL;
+ return(0);
+ }
+ else
+ {
+ uint8_t *p = (uint8_t*) *ptr;
+ *ptr += sizeof(uint32_t);
+ return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
+ }
}
-void put_short(uint16_t s, char **ptr)
+void put_uint16(uint16_t s, char **ptr)
{
(*ptr)[0] = (char)((s >> 8) & 0xFF);
(*ptr)[1] = (char)((s ) & 0xFF);
*ptr += sizeof(uint16_t);
}
-uint16_t get_short(char **ptr)
+uint16_t get_uint16(char **ptr, char *end)
{
- uint8_t *p = (uint8_t*) *ptr;
- *ptr += sizeof(uint16_t);
- return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
+ if (!*ptr || *ptr + sizeof(uint16_t) > end)
+ {
+ *ptr = NULL;
+ return(0);
+ }
+ else
+ {
+ uint8_t *p = (uint8_t*) *ptr;
+ *ptr += sizeof(uint16_t);
+ return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
+ }
}
int put_string(const char *str, char **ptr)
return 0;
}
-int get_string(char **ptr, char *buffer, int buflen)
+int get_string(char **ptr, char *end, char *buffer, int buflen)
{
- int overrun = (int)strlen(*ptr) < buflen ? 0 : -1;
- strncpy(buffer, *ptr, buflen - 1);
- buffer[buflen - 1] = '\0';
- *ptr += strlen(buffer) + 1;
- return overrun;
+ if (!*ptr)
+ {
+ *buffer = 0;
+ return(-1);
+ }
+ else
+ {
+ char *lim = buffer + buflen; // Calculate limit
+ while (*ptr < end && buffer < lim)
+ {
+ char c = *buffer++ = *(*ptr)++;
+ if (c == 0) return(0); // Success
+ }
+ if (buffer == lim) buffer--;
+ *buffer = 0; // Failed, so terminate string,
+ *ptr = NULL; // clear pointer,
+ return(-1); // and return failure indication
+ }
}
void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr)
*ptr += rdlen;
}
-char *get_rdata(char **ptr, int rdlen)
+char *get_rdata(char **ptr, char *end, int rdlen)
{
- char *rd = *ptr;
- *ptr += rdlen;
- return rd;
+ if (!*ptr || *ptr + rdlen > end)
+ {
+ *ptr = NULL;
+ return(0);
+ }
+ else
+ {
+ char *rd = *ptr;
+ *ptr += rdlen;
+ return rd;
+ }
}
void ConvertHeaderBytes(ipc_msg_hdr *hdr)
{
hdr->version = htonl(hdr->version);
hdr->datalen = htonl(hdr->datalen);
- hdr->flags = htonl(hdr->flags);
+ hdr->ipc_flags = htonl(hdr->ipc_flags);
hdr->op = htonl(hdr->op );
hdr->reg_index = htonl(hdr->reg_index);
}
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
+ * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log: dnssd_ipc.h,v $
+Revision 1.40 2007/09/07 20:56:03 cheshire
+Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32"
+
+Revision 1.39 2007/08/18 01:02:04 mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
+
+Revision 1.38 2007/08/08 22:34:59 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+
+Revision 1.37 2007/07/28 00:00:43 cheshire
+Renamed CompileTimeAssertionCheck structure for consistency with others
+
+Revision 1.36 2007/07/23 22:12:53 cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
+
+Revision 1.35 2007/05/23 18:59:22 cheshire
+Remove unnecessary IPC_FLAGS_REUSE_SOCKET
+
+Revision 1.34 2007/05/22 01:07:42 cheshire
+<rdar://problem/3563675> API: Need a way to get version/feature information
+
+Revision 1.33 2007/05/18 23:55:22 cheshire
+<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
+
+Revision 1.32 2007/05/18 20:31:20 cheshire
+Rename port_mapping_create_request to port_mapping_request
+
+Revision 1.31 2007/05/18 17:56:20 cheshire
+Rename port_mapping_create_reply_op to port_mapping_reply_op
+
+Revision 1.30 2007/05/16 01:06:52 cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
+
+Revision 1.29 2007/05/15 21:57:16 cheshire
+<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
+assuming that all negative values (or zero!) are invalid socket numbers
+
+Revision 1.28 2007/03/21 19:01:57 cheshire
+<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
+
+Revision 1.27 2006/10/27 00:38:22 cheshire
+Strip accidental trailing whitespace from lines
+
+Revision 1.26 2006/09/27 00:44:36 herscher
+<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
+
+Revision 1.25 2006/09/26 01:51:07 herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
+
+Revision 1.24 2006/09/18 19:21:42 cheshire
+<rdar://problem/4737048> gcc's structure padding breaks Bonjour APIs on
+64-bit clients; need to declare ipc_msg_hdr structure "packed"
+
+Revision 1.23 2006/08/14 23:05:53 cheshire
+Added "tab-width" emacs header line
+
+Revision 1.22 2006/06/28 08:56:26 cheshire
+Added "_op" to the end of the operation code enum values,
+to differentiate them from the routines with the same names
+
Revision 1.21 2005/09/29 06:38:13 herscher
Remove #define MSG_WAITALL on Windows. We don't use this macro anymore, and it's presence causes warnings to be emitted when compiling against the latest Microsoft Platform SDK.
#include "dns_sd.h"
-
//
// Common cross platform services
//
#if defined(WIN32)
# include <winsock2.h>
# define dnssd_InvalidSocket INVALID_SOCKET
+# define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
# define dnssd_EWOULDBLOCK WSAEWOULDBLOCK
# define dnssd_EINTR WSAEINTR
# define dnssd_sock_t SOCKET
# define dnssd_socklen_t int
-# define dnssd_sockbuf_t const char*
# define dnssd_close(sock) closesocket(sock)
# define dnssd_errno() WSAGetLastError()
# define ssize_t int
# include <sys/socket.h>
# include <netinet/in.h>
# define dnssd_InvalidSocket -1
+# define dnssd_SocketValid(s) ((s) >= 0)
# define dnssd_EWOULDBLOCK EWOULDBLOCK
# define dnssd_EINTR EINTR
# define dnssd_EPIPE EPIPE
# define dnssd_sock_t int
# define dnssd_socklen_t unsigned int
-# define dnssd_sockbuf_t const char*
# define dnssd_close(sock) close(sock)
# define dnssd_errno() errno
#endif
# endif
# define LISTENQ 100
// longest legal control path length
-# define MAX_CTLPATH 256
+# define MAX_CTLPATH 256
# define dnssd_sockaddr_t struct sockaddr_un
#endif
-
-//#define UDSDEBUG // verbose debug output
-
// Compatibility workaround
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
// IPC data encoding constants and types
#define VERSION 1
#define IPC_FLAGS_NOREPLY 1 // set flag if no asynchronous replies are to be sent to client
-#define IPC_FLAGS_REUSE_SOCKET 2 // set flag if synchronous errors are to be sent via the primary socket
- // (if not set, first string in message buffer must be path to error socket
+
+// Structure packing macro. If we're not using GNUC, it's not fatal. Most compilers naturally pack the on-the-wire
+// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
+// correctly, our compile-time assertion checks will catch it and prevent inadvertent generation of non-working code.
+#ifndef packedstruct
+ #if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
+ #define packedstruct struct __attribute__((__packed__))
+ #define packedunion union __attribute__((__packed__))
+ #else
+ #define packedstruct struct
+ #define packedunion union
+ #endif
+#endif
typedef enum
{
- connection = 1, // connected socket via DNSServiceConnect()
- reg_record_request, // reg/remove record only valid for connected sockets
+ request_op_none = 0, // No request yet received on this connection
+ connection_request = 1, // connected socket via DNSServiceConnect()
+ reg_record_request, // reg/remove record only valid for connected sockets
remove_record_request,
enumeration_request,
reg_service_request,
reconfirm_record_request,
add_record_request,
update_record_request,
- setdomain_request
+ setdomain_request, // Up to here is in Tiger and B4W 1.0.3
+ getproperty_request, // New in B4W 1.0.4
+ port_mapping_request, // New in Leopard and B4W 2.0
+ addrinfo_request,
+
+ cancel_request = 63
} request_op_t;
typedef enum
{
- enumeration_reply = 64,
- reg_service_reply,
- browse_reply,
- resolve_reply,
- query_reply,
- reg_record_reply
+ enumeration_reply_op = 64,
+ reg_service_reply_op,
+ browse_reply_op,
+ resolve_reply_op,
+ query_reply_op,
+ reg_record_reply_op, // Up to here is in Tiger and B4W 1.0.3
+ getproperty_reply_op, // New in B4W 1.0.4
+ port_mapping_reply_op, // New in Leopard and B4W 2.0
+ addrinfo_reply_op
} reply_op_t;
-typedef struct ipc_msg_hdr_struct ipc_msg_hdr;
-
-// client stub callback to process message from server and deliver results to
-// client application
-
-typedef void (*process_reply_callback)
- (
- DNSServiceRef sdr,
- ipc_msg_hdr *hdr,
- char *msg
- );
+#if defined(_WIN64)
+# pragma pack(4)
+#endif
-// allow 64-bit client to interoperate w/ 32-bit daemon
-typedef union
+// Define context object big enough to hold a 64-bit pointer,
+// to accomodate 64-bit clients communicating with 32-bit daemon.
+// There's no reason for the daemon to ever be a 64-bit process, but its clients might be
+typedef packedunion
{
void *context;
- uint32_t ptr64[2];
+ uint32_t u32[2];
} client_context_t;
-typedef struct ipc_msg_hdr_struct
+typedef packedstruct
{
uint32_t version;
uint32_t datalen;
- uint32_t flags;
+ uint32_t ipc_flags;
uint32_t op; // request_op_t or reply_op_t
client_context_t client_context; // context passed from client, returned by server in corresponding reply
uint32_t reg_index; // identifier for a record registered via DNSServiceRegisterRecord() on a
// socket connected by DNSServiceConnect(). Must be unique in the scope of the connection, such that and
// index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord())
- } ipc_msg_hdr_struct;
+ } ipc_msg_hdr;
-// it is advanced to point to the next field, or the end of the message
// routines to write to and extract data from message buffers.
// caller responsible for bounds checking.
// ptr is the address of the pointer to the start of the field.
// it is advanced to point to the next field, or the end of the message
-void put_long(const uint32_t l, char **ptr);
-uint32_t get_long(char **ptr);
+void put_uint32(const uint32_t l, char **ptr);
+uint32_t get_uint32(char **ptr, char *end);
-void put_short(uint16_t s, char **ptr);
-uint16_t get_short(char **ptr);
+void put_uint16(uint16_t s, char **ptr);
+uint16_t get_uint16(char **ptr, char *end);
-#define put_flags put_long
-#define get_flags get_long
+#define put_flags put_uint32
+#define get_flags get_uint32
-#define put_error_code put_long
-#define get_error_code get_long
+#define put_error_code put_uint32
+#define get_error_code get_uint32
int put_string(const char *str, char **ptr);
-int get_string(char **ptr, char *buffer, int buflen);
+int get_string(char **ptr, char *end, char *buffer, int buflen);
void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
-char *get_rdata(char **ptr, int rdlen); // return value is rdata pointed to by *ptr -
+char *get_rdata(char **ptr, char *end, int rdlen); // return value is rdata pointed to by *ptr -
// rdata is not copied from buffer.
void ConvertHeaderBytes(ipc_msg_hdr *hdr);
+struct CompileTimeAssertionChecks_dnssd_ipc
+ {
+ // Check that the compiler generated our on-the-wire packet format structure definitions
+ // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
+ char assert0[(sizeof(client_context_t) == 8) ? 1 : -1];
+ char assert1[(sizeof(ipc_msg_hdr) == 28) ? 1 : -1];
+ };
+
#endif // DNSSD_IPC_H
+.\" -*- tab-width: 4 -*-
+.\"
.\" Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
.\"
-.\" @APPLE_LICENSE_HEADER_START@
+.\" Licensed under the Apache License, Version 2.0 (the "License");
+.\" you may not use this file except in compliance with the License.
+.\" You may obtain a copy of the License at
.\"
-.\" This file contains Original Code and/or Modifications of Original Code
-.\" as defined in and that are subject to the Apple Public Source License
-.\" Version 2.0 (the 'License'). You may not use this file except in
-.\" compliance with the License. Please obtain a copy of the License at
-.\" http://www.opensource.apple.com/apsl/ and read it before using this
-.\" file.
+.\" http://www.apache.org/licenses/LICENSE-2.0
.\"
-.\" The Original Code and all software distributed under the License are
-.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-.\" Please see the License for the specific language governing rights and
+.\" Unless required by applicable law or agreed to in writing, software
+.\" distributed under the License is distributed on an "AS IS" BASIS,
+.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+.\" See the License for the specific language governing permissions and
.\" limitations under the License.
-.\"
-.\" @APPLE_LICENSE_HEADER_END@
.\"
.\" $Log: mDNS.1,v $
+.\" Revision 1.8 2006/08/14 23:24:56 cheshire
+.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+.\"
.\" Revision 1.7 2005/02/16 02:29:32 cheshire
.\" Update terminology
.\"
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
File: mDNSDebug.c
Change History (most recent first):
$Log: mDNSDebug.c,v $
+Revision 1.12 2007/10/01 19:06:19 cheshire
+Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at
+
+Revision 1.11 2007/07/27 20:19:56 cheshire
+For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG
+
+Revision 1.10 2007/06/15 21:54:51 cheshire
+<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
+
+Revision 1.9 2007/04/05 19:52:32 cheshire
+Display correct ident in syslog messages (i.e. in dnsextd, ProgramName is not "mDNSResponder")
+
+Revision 1.8 2007/01/20 01:43:27 cheshire
+<rdar://problem/4058383> Should not write log messages to /dev/console
+
+Revision 1.7 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.6 2005/01/27 22:57:56 cheshire
Fix compile errors on gcc4
#include "mDNSEmbeddedAPI.h"
+mDNSexport LogLevel_t mDNS_LogLevel = MDNS_LOG_INITIAL_LEVEL;
+
#if MDNS_DEBUGMSGS
mDNSexport int mDNS_DebugMode = mDNStrue;
#else
}
else // else, in production mode, we write to syslog
{
- openlog(ident, LOG_CONS | LOG_PERROR | logoptflags, LOG_DAEMON);
+ openlog(ident, LOG_CONS | logoptflags, LOG_DAEMON);
syslog(LOG_ERR, "%s", buffer);
closelog();
}
va_start(ptr,format);
buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
va_end(ptr);
- WriteLogMsg("mDNSResponder", buffer, 0);
+ WriteLogMsg(ProgramName, buffer, 0);
}
// Log message with specified ident string at the start
va_end(ptr);
WriteLogMsg("", buffer, 0);
}
+
+mDNSlocal const char *CStringForLogLevel(LogLevel_t level)
+ {
+ switch (level)
+ {
+ case MDNS_LOG_NONE: return "MDNS_LOG_NONE";
+// case MDNS_LOG_ERROR: return "MDNS_LOG_ERROR";
+// case MDNS_LOG_WARN: return "MDNS_LOG_WARN";
+// case MDNS_LOG_INFO: return "MDNS_LOG_INFO";
+// case MDNS_LOG_DEBUG: return "MDNS_LOG_DEBUG";
+ case MDNS_LOG_VERBOSE_DEBUG: return "MDNS_LOG_VERBOSE_DEBUG";
+ default: return "MDNS_LOG_UNKNOWN";
+ }
+ }
+
+mDNSexport void SigLogLevel(void)
+ {
+ if (mDNS_LogLevel < MDNS_LOG_VERBOSE_DEBUG) mDNS_LogLevel++;
+ else mDNS_LogLevel = MDNS_LOG_NONE;
+ LogMsg("Log Level Changed to %s", CStringForLogLevel(mDNS_LogLevel));
+ }
+.\" -*- tab-width: 4 -*-
+.\"
.\" Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved.
.\"
-.\" @APPLE_LICENSE_HEADER_START@
+.\" Licensed under the Apache License, Version 2.0 (the "License");
+.\" you may not use this file except in compliance with the License.
+.\" You may obtain a copy of the License at
.\"
-.\" This file contains Original Code and/or Modifications of Original Code
-.\" as defined in and that are subject to the Apple Public Source License
-.\" Version 2.0 (the 'License'). You may not use this file except in
-.\" compliance with the License. Please obtain a copy of the License at
-.\" http://www.opensource.apple.com/apsl/ and read it before using this
-.\" file.
+.\" http://www.apache.org/licenses/LICENSE-2.0
.\"
-.\" The Original Code and all software distributed under the License are
-.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-.\" Please see the License for the specific language governing rights and
+.\" Unless required by applicable law or agreed to in writing, software
+.\" distributed under the License is distributed on an "AS IS" BASIS,
+.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+.\" See the License for the specific language governing permissions and
.\" limitations under the License.
-.\"
-.\" @APPLE_LICENSE_HEADER_END@
.\"
.\" $Log: mDNSResponder.8,v $
+.\" Revision 1.8 2006/10/06 17:31:33 mkrochma
+.\" <rdar://problem/4769407> Typo in man page for mDNSResponder(8)
+.\"
+.\" Revision 1.7 2006/08/14 23:24:56 cheshire
+.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+.\"
.\" Revision 1.6 2005/02/10 22:35:28 cheshire
.\" <rdar://problem/3727944> Update name
.\"
manually.
.Pp
To examine
-.Nm Ns 's internal state, for debugging and disagnostic purposes,
+.Nm Ns 's internal state, for debugging and diagnostic purposes,
send it a SIGINFO signal, and it will then dump a snapshot summary
of its internal state to
.Pa /var/log/system.log Ns , e.g.
*
* Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- Change History (most recent first):
+ Change History (most recent first):
$Log: uds_daemon.c,v $
-Revision 1.199.2.1 2007/01/06 03:22:03 cheshire
-<rdar://problem/4912058> Crash at resolve_result_callback + 192
-
-Revision 1.199 2006/06/28 08:53:39 cheshire
-Added (commented out) debugging messages
-
-Revision 1.198 2006/06/27 20:16:07 cheshire
-Fix code layout
-
-Revision 1.197 2006/05/18 01:32:35 cheshire
-<rdar://problem/4472706> iChat: Lost connection with Bonjour
-(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
-
-Revision 1.196 2006/05/05 07:07:13 cheshire
-<rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
-
-Revision 1.195 2006/04/25 20:56:28 mkrochma
-Added comment about previous checkin
-
-Revision 1.194 2006/04/25 18:29:36 mkrochma
-Workaround for warning: unused variable 'status' when building mDNSPosix
-
-Revision 1.193 2006/03/19 17:14:38 cheshire
-<rdar://problem/4483117> Need faster purging of stale records
-read_rr_from_ipc_msg was not setting namehash and rdatahash
-
-Revision 1.192 2006/03/18 20:58:32 cheshire
-Misplaced curly brace
-
-Revision 1.191 2006/03/10 22:19:43 cheshire
-Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
-
-Revision 1.190 2006/03/10 21:56:12 cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
-when the TXT data changes, and then immediately afterwards a second callback with the new port number
-This change suppresses the first unneccessary (and confusing) callback
+Revision 1.366 2007/10/10 00:48:54 cheshire
+<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
-Revision 1.189 2006/01/06 00:56:31 cheshire
-<rdar://problem/4400573> Should remove PID file on exit
+Revision 1.365 2007/10/06 03:25:23 cheshire
+<rdar://problem/5525267> MacBuddy exits abnormally when clicking "Continue" in AppleConnect pane
-Revision 1.188 2005/10/11 22:15:03 cheshire
-<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
-Only compile uds_validatelists() when building for Mac OS X
+Revision 1.364 2007/10/06 03:20:16 cheshire
+Improved LogOperation debugging messages
-Revision 1.187 2005/10/11 20:30:27 cheshire
-<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
+Revision 1.363 2007/10/05 23:24:52 cheshire
+Improved LogOperation messages about separate error return socket
-Revision 1.186 2005/09/12 07:11:53 herscher
-<rdar://problem/4248878> Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms.
+Revision 1.362 2007/10/05 22:11:58 cheshire
+Improved "send_msg ERROR" debugging message
-Revision 1.185 2005/07/29 00:55:10 ksekar
-Removed validation check in uds_validatelists which generated false alarms
+Revision 1.361 2007/10/04 20:45:18 cheshire
+<rdar://problem/5518381> Race condition in kDNSServiceFlagsShareConnection-mode call handling
-Revision 1.184 2005/07/04 22:40:26 cheshire
-Additional debugging code to help catch memory corruption
+Revision 1.360 2007/10/01 23:24:46 cheshire
+SIGINFO output was mislabeling mDNSInterface_Any queries as unicast queries
-Revision 1.183 2005/06/13 22:39:11 cheshire
-<rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
+Revision 1.359 2007/09/30 00:09:27 cheshire
+<rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
-Revision 1.182 2005/03/21 00:39:31 shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
+Revision 1.358 2007/09/29 20:08:06 cheshire
+Fixed typo in comment
-Revision 1.181 2005/03/20 20:21:32 shersche
-<rdar://problem/4056827> mDNSResponder crashes when incorrect interface index is passed to DNSServiceRegister()
-Text record length and data parameters must be initialized to 0 and NULL to ensure that the service request
-object is cleaned up correctly when encountering an interface index error.
+Revision 1.357 2007/09/27 22:10:04 cheshire
+Add LogOperation line for DNSServiceRegisterRecord callbacks
-Revision 1.180 2005/03/10 00:13:12 cheshire
-<rdar://problem/4043098> DNSServiceBrowse no longer returning error codes for invalid types
-In handle_browse_request(), mStatus err was being set correctly if an error occurred,
-but the end of the function returned mStatus_NoError intead of err.
+Revision 1.356 2007/09/26 21:29:30 cheshire
+Improved question list SIGINFO output
-Revision 1.179 2005/03/04 02:47:26 ksekar
-<rdar://problem/4026393> SCPreference domains disappear from enumeration when moving out from firewall
+Revision 1.355 2007/09/26 01:54:34 mcguire
+Debugging: In SIGINFO output, show ClientTunnel query interval, which is how we determine whether a query is still active
-Revision 1.178 2005/02/25 19:35:38 ksekar
-<rdar://problem/4023750> Non-local empty string registration failures should not return errors to caller
+Revision 1.354 2007/09/26 01:26:31 cheshire
+<rdar://problem/5501567> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
+Need to call SendServiceRemovalNotification *before* backpointer is cleared
-Revision 1.177 2005/02/25 03:05:41 cheshire
-Change "broken pipe" message to debugf()
+Revision 1.353 2007/09/25 20:46:33 cheshire
+Include DNSServiceRegisterRecord operations in SIGINFO output
-Revision 1.176 2005/02/24 18:44:45 ksekar
-<rdar://problem/4018516> Printer Sharing does not get re-registered with wide-area
+Revision 1.352 2007/09/25 20:23:40 cheshire
+<rdar://problem/5501567> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
+Need to clear si->request backpointer before calling mDNS_DeregisterService(&mDNSStorage, &si->srs);
-Revision 1.175 2005/02/21 21:31:25 ksekar
-<rdar://problem/4015162> changed LogMsg to debugf
+Revision 1.351 2007/09/25 18:20:34 cheshire
+Changed name of "free_service_instance" to more accurate "unlink_and_free_service_instance"
-Revision 1.174 2005/02/20 01:41:17 cheshire
-Fix compiler signed/unsigned warning
+Revision 1.350 2007/09/24 23:54:52 mcguire
+Additional list checking in uds_validatelists()
-Revision 1.173 2005/02/18 01:26:42 cheshire
-<rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
-Log additional information about failed client
+Revision 1.349 2007/09/24 06:01:00 cheshire
+Debugging: In SIGINFO output, show NAT Traversal time values in seconds rather than platform ticks
-Revision 1.172 2005/02/18 00:58:35 cheshire
-<rdar://problem/4012162> "Could not write data to client after 60 seconds" message could be more helpful
+Revision 1.348 2007/09/24 05:02:41 cheshire
+Debugging: In SIGINFO output, indicate explicitly when a given section is empty
-Revision 1.171 2005/02/18 00:43:12 cheshire
-<rdar://problem/4010245> mDNSResponder should auto-truncate service names that are too long
+Revision 1.347 2007/09/21 02:04:33 cheshire
+<rdar://problem/5440831> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
-Revision 1.170 2005/02/16 01:15:02 cheshire
-Improve LogOperation() debugging messages for DNSServiceBrowse and DNSServiceRegister
+Revision 1.346 2007/09/19 22:47:25 cheshire
+<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
-Revision 1.169 2005/02/08 01:57:14 cheshire
-More detailed error reporting in udsserver_init()
+Revision 1.345 2007/09/19 20:32:29 cheshire
+<rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
-Revision 1.168 2005/02/03 00:44:37 cheshire
-<rdar://problem/3986663> DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL
+Revision 1.344 2007/09/19 19:27:50 cheshire
+<rdar://problem/5492182> Improved diagnostics when daemon can't connect to error return path socket
-Revision 1.167 2005/02/02 02:19:32 cheshire
-Add comment explaining why unlink(MDNS_UDS_SERVERPATH); fails
+Revision 1.343 2007/09/18 21:42:30 cheshire
+To reduce programming mistakes, renamed ExtPort to RequestedPort
-Revision 1.166 2005/02/01 19:58:52 ksekar
-Shortened cryptic "broken pipe" syslog message
+Revision 1.342 2007/09/14 22:38:20 cheshire
+Additional list checking in uds_validatelists()
-Revision 1.165 2005/02/01 19:56:47 ksekar
-Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording
+Revision 1.341 2007/09/13 00:16:43 cheshire
+<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-Revision 1.164 2005/01/28 06:07:55 cheshire
-Don't use deliver_error() from within handle_regrecord_request()
+Revision 1.340 2007/09/12 23:03:08 cheshire
+<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-Revision 1.163 2005/01/28 01:39:16 cheshire
-Include file descriptor number in "broken pipe" message
+Revision 1.339 2007/09/12 19:22:21 cheshire
+Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
+Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-Revision 1.162 2005/01/27 23:59:20 cheshire
-Remove extraneous LogMsg
+Revision 1.338 2007/09/12 01:22:13 cheshire
+Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
-Revision 1.161 2005/01/27 22:57:56 cheshire
-Fix compile errors on gcc4
+Revision 1.337 2007/09/07 23:05:04 cheshire
+Add display of client_context field in handle_cancel_request() LogOperation message
+While loop was checking client_context.u32[2] instead of client_context.u32[1]
-Revision 1.160 2005/01/27 20:52:11 cheshire
-<rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
+Revision 1.336 2007/09/07 20:56:03 cheshire
+Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32"
-Revision 1.159 2005/01/27 01:45:25 cheshire
-<rdar://problem/3976147> mDNSResponder should never call exit(1);
+Revision 1.335 2007/09/05 22:25:01 vazquez
+<rdar://problem/5400521> update_record mDNSResponder leak
-Revision 1.158 2005/01/25 17:28:07 ksekar
-<rdar://problem/3971467> Should not return "local" twice for domain enumeration
+Revision 1.334 2007/09/05 20:43:57 cheshire
+Added LogOperation message showing fd of socket listening for incoming Unix Domain Socket client requests
-Revision 1.157 2005/01/21 02:20:39 cheshire
-Fix mistake in LogOperation() format string
+Revision 1.333 2007/08/28 23:32:35 cheshire
+Added LogOperation messages for DNSServiceNATPortMappingCreate() operations
-Revision 1.156 2005/01/19 19:15:36 ksekar
-Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
+Revision 1.332 2007/08/27 22:59:31 cheshire
+Show reg_index in DNSServiceRegisterRecord/DNSServiceRemoveRecord messages
-Revision 1.155 2005/01/19 03:00:47 cheshire
-Show Add/Rmv in DNSServiceBrowse LogOperation() message
+Revision 1.331 2007/08/27 20:29:57 cheshire
+Added SIGINFO listing of TunnelClients
-Revision 1.154 2005/01/15 00:56:42 ksekar
-<rdar://problem/3954575> Unicast services don't disappear when logging
-out of VPN
+Revision 1.330 2007/08/24 23:46:50 cheshire
+Added debugging messages and SIGINFO listing of DomainAuthInfo records
-Revision 1.153 2005/01/14 18:44:28 ksekar
-<rdar://problem/3954609> mDNSResponder is crashing when changing domains
+Revision 1.329 2007/08/18 01:02:04 mcguire
+<rdar://problem/5415593> No Bonjour services are getting registered at boot
-Revision 1.152 2005/01/13 17:16:38 ksekar
-Back out checkin 1.150 - correct fix is on clientstub side
+Revision 1.328 2007/08/15 20:18:28 vazquez
+<rdar://problem/5400521> update_record mDNSResponder leak
+Make sure we free all ExtraResourceRecords
-Revision 1.151 2005/01/11 21:06:29 ksekar
-Changed now-benign LogMsg to debugf
+Revision 1.327 2007/08/08 22:34:59 mcguire
+<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-Revision 1.150 2005/01/07 23:59:15 ksekar
-<rdar://problem/3942900> dnd-sd shows the wrong port numbers
+Revision 1.326 2007/08/01 16:09:14 cheshire
+Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-Revision 1.149 2004/12/20 23:20:35 cheshire
-<rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
-Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
+Revision 1.325 2007/07/31 21:29:41 cheshire
+<rdar://problem/5372207> System Default registration domain(s) not listed in Domain Enumeration ("dns-sd -E")
-Revision 1.148 2004/12/20 20:37:35 cheshire
-AllowRemoteQuery not set for the extras in a ServiceRecordSet
+Revision 1.324 2007/07/31 01:56:21 cheshire
+Corrected function name in log message
-Revision 1.147 2004/12/20 00:15:41 cheshire
-Include client file descriptor numbers in udsserver_info() output
+Revision 1.323 2007/07/27 23:57:23 cheshire
+Added compile-time structure size checks
-Revision 1.146 2004/12/17 05:25:47 cheshire
-<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
+Revision 1.322 2007/07/27 19:37:19 cheshire
+Moved AutomaticBrowseDomainQ into main mDNS object
-Revision 1.145 2004/12/16 21:39:46 cheshire
-Include CacheGroup objects in CacheUsed count
+Revision 1.321 2007/07/27 19:30:41 cheshire
+Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
+to properly reflect tri-state nature of the possible responses
-Revision 1.144 2004/12/16 21:27:38 ksekar
-Fixed build failures when compiled with verbose debugging messages
+Revision 1.320 2007/07/27 00:48:27 cheshire
+<rdar://problem/4700198> BTMM: Services should only get registered in .Mac domain of current user
+<rdar://problem/4731180> BTMM: Only browse in the current user's .Mac domain by default
-Revision 1.143 2004/12/16 20:13:02 cheshire
-<rdar://problem/3324626> Cache memory management improvements
+Revision 1.319 2007/07/24 17:23:33 cheshire
+<rdar://problem/5357133> Add list validation checks for debugging
-Revision 1.142 2004/12/16 08:07:33 shersche
-Fix compiler error (mixed declarations and code) on Windows
+Revision 1.318 2007/07/23 23:09:51 cheshire
+<rdar://problem/5351997> Reject oversized client requests
-Revision 1.141 2004/12/16 01:56:21 cheshire
-Improve DNSServiceEnumerateDomains syslog message
+Revision 1.317 2007/07/23 22:24:47 cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
+Additional refinements
-Revision 1.140 2004/12/14 03:02:10 ksekar
-<rdar://problem/3919016> Rare race condition can cause crash
+Revision 1.316 2007/07/23 22:12:53 cheshire
+<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-Revision 1.139 2004/12/13 21:18:45 ksekar
-Include uDNS registrations in CountPeerRegistrations
+Revision 1.315 2007/07/21 01:36:13 cheshire
+Need to also add ".local" as automatic browsing domain
-Revision 1.138 2004/12/13 18:23:18 ksekar
-<rdar://problem/3915805> mDNSResponder error when quitting iChat -
-don't close sockets delivering errors to blocked clients
+Revision 1.314 2007/07/20 20:12:37 cheshire
+Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
-Revision 1.137 2004/12/13 00:09:22 ksekar
-<rdar://problem/3915805> mDNSResponder error when quitting iChat
+Revision 1.313 2007/07/20 00:54:21 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Revision 1.136 2004/12/11 01:52:10 cheshire
-<rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
+Revision 1.312 2007/07/11 03:06:43 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Revision 1.135 2004/12/10 20:46:37 cheshire
-Change LogOperation message to debugf
+Revision 1.311 2007/07/06 21:19:18 cheshire
+Add list of NAT traversals to SIGINFO output
-Revision 1.134 2004/12/10 13:19:37 cheshire
-Add verbosedebugf() logging message in CountPeerRegistrations()
+Revision 1.310 2007/07/03 19:56:50 cheshire
+Add LogOperation message for DNSServiceSetDefaultDomainForUser
-Revision 1.133 2004/12/10 05:27:26 cheshire
-<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
+Revision 1.309 2007/06/29 23:12:49 vazquez
+<rdar://problem/5294103> Stop using generate_final_fatal_reply_with_garbage
-Revision 1.132 2004/12/10 04:28:28 cheshire
-<rdar://problem/3914406> User not notified of name changes for services using new UDS API
+Revision 1.308 2007/06/29 00:10:07 vazquez
+<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-Revision 1.131 2004/12/10 02:09:25 cheshire
-<rdar://problem/3898376> Modify default TTLs
+Revision 1.307 2007/05/25 00:25:44 cheshire
+<rdar://problem/5227737> Need to enhance putRData to output all current known types
-Revision 1.130 2004/12/10 00:55:24 cheshire
-Add full name and type to LogOperation messages for DNSServiceAddRecord/UpdateRecord/RemoveRecord
+Revision 1.306 2007/05/24 22:31:35 vazquez
+Bug #: 4272956
+Reviewed by: Stuart Cheshire
+<rdar://problem/4272956> WWDC API: Return ADD/REMOVE events in registration callback
-Revision 1.129 2004/12/09 03:17:23 ksekar
-<rdar://problem/3910435> DomainEnumeration interface index should be zero
+Revision 1.305 2007/05/23 18:59:22 cheshire
+Remove unnecessary IPC_FLAGS_REUSE_SOCKET
-Revision 1.128 2004/12/07 21:26:05 ksekar
-<rdar://problem/3908336> DNSServiceRegisterRecord() can crash on deregistration
+Revision 1.304 2007/05/22 01:07:42 cheshire
+<rdar://problem/3563675> API: Need a way to get version/feature information
-Revision 1.127 2004/12/07 20:42:34 cheshire
-Add explicit context parameter to mDNS_RemoveRecordFromService()
+Revision 1.303 2007/05/22 00:32:58 cheshire
+Make a send_all() subroutine -- will be helpful for implementing DNSServiceGetProperty(DaemonVersion)
-Revision 1.126 2004/12/07 17:23:55 ksekar
-Fixed LogOperation
+Revision 1.302 2007/05/21 18:54:54 cheshire
+Add "Cancel" LogOperation message when we get a cancel_request command over the UDS
-Revision 1.125 2004/12/06 21:15:23 ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
+Revision 1.301 2007/05/18 23:55:22 cheshire
+<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
-Revision 1.124 2004/11/30 02:19:14 cheshire
-<rdar://problem/3827971> Raise maxfds.rlim_cur for mDNSResponder
+Revision 1.300 2007/05/18 21:27:11 cheshire
+Rename connected_registration_termination to connection_termination
-Revision 1.123 2004/11/29 23:50:57 cheshire
-Checkin 1.122 not necessary
+Revision 1.299 2007/05/18 21:24:34 cheshire
+Rename rstate to request
-Revision 1.122 2004/11/24 17:55:01 ksekar
-Added log message clarifying <rdar://problem/3869241> For unicast operations, verify that service types are legal
+Revision 1.298 2007/05/18 21:22:35 cheshire
+Convert uint16_t etc. to their locally-defined equivalents, like the rest of the core code
-Revision 1.121 2004/11/24 04:45:52 cheshire
-Spelling mistake
+Revision 1.297 2007/05/18 20:33:11 cheshire
+Avoid declaring lots of uninitialized variables in read_rr_from_ipc_msg
-Revision 1.120 2004/11/24 00:10:44 cheshire
-<rdar://problem/3869241> For unicast operations, verify that service types are legal
+Revision 1.296 2007/05/18 19:04:19 cheshire
+Rename msgdata to msgptr (may be modified); rename (currently unused) bufsize to msgend
-Revision 1.119 2004/11/23 23:54:17 ksekar
-<rdar://problem/3890318> Wide-Area DNSServiceRegisterRecord() failures
-can crash mDNSResponder
+Revision 1.295 2007/05/18 17:57:13 cheshire
+Reorder functions in file to arrange them in logical groups; added "#pragma mark" headers for each group
-Revision 1.118 2004/11/23 22:33:01 cheshire
-<rdar://problem/3654910> Remove temporary workaround code for iChat
+Revision 1.294 2007/05/17 20:58:22 cheshire
+<rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
-Revision 1.117 2004/11/23 20:23:10 ksekar
-Fixed LogOperation that causes crash on connected service deregistrations
+Revision 1.293 2007/05/17 19:46:20 cheshire
+Routine name deliver_async_error() is misleading. What it actually does is write a message header
+(containing an error code) followed by 256 bytes of garbage zeroes onto a client connection,
+thereby trashing it and making it useless for any subsequent communication. It's destructive,
+and not very useful. Changing name to generate_final_fatal_reply_with_garbage().
-Revision 1.116 2004/11/23 03:39:47 cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
+Revision 1.292 2007/05/16 01:06:52 cheshire
+<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-Revision 1.115 2004/11/13 00:12:53 ksekar
-Fixed some LogOperation printf converstions for debug builds.
+Revision 1.291 2007/05/15 21:57:16 cheshire
+<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
+assuming that all negative values (or zero!) are invalid socket numbers
-Revision 1.114 2004/11/12 18:25:45 shersche
-Tidy up cross platform usleep code fragment.
+Revision 1.290 2007/05/10 23:30:57 cheshire
+<rdar://problem/4084490> Only one browse gets remove events when disabling browse domain
-Revision 1.113 2004/11/12 03:21:41 rpantos
-rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
+Revision 1.289 2007/05/02 22:18:08 cheshire
+Renamed NATTraversalInfo_struct context to NATTraversalContext
-Revision 1.112 2004/11/11 16:58:32 ksekar
-Removed unused code (previously wrapped in #if 0)
+Revision 1.288 2007/04/30 21:33:39 cheshire
+Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
+is iterating through the m->ServiceRegistrations list
-Revision 1.111 2004/11/05 22:47:37 shersche
-Conditionally compile usleep(1000) to be Sleep(1) on Windows
-Submitted by: Pavel Repin <prepin@gmail.com>
+Revision 1.287 2007/04/27 19:03:22 cheshire
+Check q->LongLived not q->llq to tell if a query is LongLived
-Revision 1.110 2004/11/05 19:56:56 ksekar
-<rdar://problem/3862646> We no longer need to browse .Mac domains by
-default - changed #if 0 to more descriptive #ifdef _HAVE_SETDOMAIN_SUPPORT_
+Revision 1.286 2007/04/26 16:00:01 cheshire
+Show interface number in DNSServiceBrowse RESULT output
-Revision 1.109 2004/11/04 03:40:45 cheshire
-More debugging messages
+Revision 1.285 2007/04/22 19:03:39 cheshire
+Minor code tidying
-Revision 1.108 2004/11/03 02:25:51 cheshire
-<rdar://problem/3324137> Conflict for Computer Name should update *all* empty string services, not just the one with the conflict
+Revision 1.284 2007/04/22 06:02:03 cheshire
+<rdar://problem/4615977> Query should immediately return failure when no server
-Revision 1.107 2004/11/02 19:39:23 ksekar
-<rdar://problem/3862646> We no longer need to browse .Mac domains by default
+Revision 1.283 2007/04/21 21:47:47 cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
-Revision 1.106 2004/11/02 02:12:21 cheshire
-<rdar://problem/3839111> Remove unnecessary memory allocations
+Revision 1.282 2007/04/20 21:17:24 cheshire
+For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-Revision 1.105 2004/10/28 19:07:19 cheshire
-Add some more debugging checks and improved LogOperation() messages
+Revision 1.281 2007/04/19 23:25:20 cheshire
+Added debugging message
-Revision 1.104 2004/10/26 18:53:15 cheshire
-Avoid unused variable warning
+Revision 1.280 2007/04/17 19:21:29 cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
-Revision 1.103 2004/10/26 07:15:55 cheshire
-Add file descriptor number to all LogOperation messages
+Revision 1.279 2007/04/16 21:53:49 cheshire
+Improve display of negative cache entries
-Revision 1.102 2004/10/26 06:11:42 cheshire
-Add improved logging to aid in diagnosis of <rdar://problem/3842714> mDNSResponder crashed
+Revision 1.278 2007/04/16 20:49:40 cheshire
+Fix compile errors for mDNSPosix build
-Revision 1.101 2004/10/26 04:31:44 cheshire
-Rename CountSubTypes() as ChopSubTypes()
+Revision 1.277 2007/04/05 22:55:36 cheshire
+<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-Revision 1.100 2004/10/26 01:17:48 cheshire
-Use "#if 0" instead of commenting out code
+Revision 1.276 2007/04/05 19:20:13 cheshire
+Non-blocking mode not being set correctly -- was clobbering other flags
-Revision 1.99 2004/10/19 21:33:22 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
+Revision 1.275 2007/04/04 21:21:25 cheshire
+<rdar://problem/4546810> Fix crash: In regservice_callback service_instance was being referenced after being freed
-Revision 1.98 2004/10/14 01:59:33 cheshire
-<rdar://problem/3839208> UDS resolves don't work for uDNS services
+Revision 1.274 2007/04/04 01:30:42 cheshire
+<rdar://problem/5075200> DNSServiceAddRecord is failing to advertise NULL record
+Add SIGINFO output lising our advertised Authoritative Records
-Revision 1.97 2004/10/13 00:58:35 cheshire
-<rdar://problem/3832738> Registering a proxy doesn't work
+Revision 1.273 2007/04/04 00:03:27 cheshire
+<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-Revision 1.96 2004/09/30 00:25:00 ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
+Revision 1.272 2007/04/03 20:10:32 cheshire
+Show ADD/RMV in DNSServiceQueryRecord log message instead of just "RESULT"
-Revision 1.95 2004/09/26 23:20:36 ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.271 2007/04/03 19:22:32 cheshire
+Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly
-Revision 1.94 2004/09/22 18:27:06 ksekar
-<rdar://problem/3811427> allow DNSServiceAddRecord to pass zero to get
-default record TTL
+Revision 1.270 2007/03/30 21:55:30 cheshire
+Added comments
-Revision 1.93 2004/09/22 02:39:44 cheshire
-<rdar://problem/3810757> Allow DNSServiceRegisterRecord to pass zero to get default record TTL
+Revision 1.269 2007/03/29 01:31:44 cheshire
+Faulty logic was incorrectly suppressing some NAT port mapping callbacks
-Revision 1.92 2004/09/22 02:34:04 cheshire
-Rename parameter "ttl" to "GetTTL" for clarity
+Revision 1.268 2007/03/29 00:13:58 cheshire
+Remove unnecessary fields from service_instance structure: autoname, autorename, allowremotequery, name
-Revision 1.91 2004/09/22 02:25:43 cheshire
-Fix spelling errors
+Revision 1.267 2007/03/28 20:59:27 cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-Revision 1.90 2004/09/21 23:40:12 ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
+Revision 1.266 2007/03/28 15:56:37 cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-Revision 1.89 2004/09/21 23:29:51 cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
+Revision 1.265 2007/03/27 22:52:07 cheshire
+Fix crash in udsserver_automatic_browse_domain_changed
-Revision 1.88 2004/09/21 23:12:46 cheshire
-Reorder initialization of question fields to match structure order
+Revision 1.264 2007/03/27 00:49:40 cheshire
+Should use mallocL, not plain malloc
-Revision 1.87 2004/09/21 22:18:33 cheshire
-In SIGINFO output, display a '-' next to records that have the Unique bit set
+Revision 1.263 2007/03/27 00:45:01 cheshire
+Removed unnecessary "void *termination_context" pointer
-Revision 1.86 2004/09/21 21:05:11 cheshire
-Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
-into mDNSShared/uds_daemon.c
+Revision 1.262 2007/03/27 00:40:43 cheshire
+Eliminate resolve_termination_t as a separately-allocated structure, and make it part of the request_state union
-Revision 1.85 2004/09/18 01:11:58 ksekar
-<rdar://problem/3806734> Add a user's default domain to empty-string browse list
+Revision 1.261 2007/03/27 00:29:00 cheshire
+Eliminate queryrecord_request data as a separately-allocated structure, and make it part of the request_state union
-Revision 1.84 2004/09/17 01:08:55 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.260 2007/03/27 00:18:42 cheshire
+Eliminate enum_termination_t and domain_enum_t as separately-allocated structures,
+and make them part of the request_state union
-Revision 1.83 2004/09/16 23:26:33 cheshire
-Move version check inside preceeding "if" that checks we have a complete header
+Revision 1.259 2007/03/26 23:48:16 cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
+Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
-Revision 1.82 2004/09/16 23:14:25 cheshire
-Changes for Windows compatibility
+Revision 1.258 2007/03/24 00:40:04 cheshire
+Minor code cleanup
-Revision 1.81 2004/09/16 21:46:38 ksekar
-<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
+Revision 1.257 2007/03/24 00:23:12 cheshire
+Eliminate port_mapping_info_t as a separately-allocated structure, and make it part of the request_state union
-Revision 1.80 2004/09/16 01:58:23 cheshire
-Fix compiler warnings
+Revision 1.256 2007/03/24 00:07:18 cheshire
+Eliminate addrinfo_info_t as a separately-allocated structure, and make it part of the request_state union
-Revision 1.79 2004/09/16 00:24:49 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.255 2007/03/23 23:56:14 cheshire
+Move list of record registrations into the request_state union
-Revision 1.78 2004/09/15 21:44:20 cheshire
-<rdar://problem/3681031> Randomize initial timenow_adjust value in mDNS_Init
-Show time value in log to help diagnose errors
+Revision 1.254 2007/03/23 23:48:56 cheshire
+Eliminate service_info as a separately-allocated structure, and make it part of the request_state union
-Revision 1.77 2004/09/15 00:19:18 cheshire
-<rdar://problem/3785823> read_rr_from_ipc_msg should use mDNS_SetupResourceRecord()
+Revision 1.253 2007/03/23 23:04:29 cheshire
+Eliminate browser_info_t as a separately-allocated structure, and make it part of request_state
-Revision 1.76 2004/09/02 06:39:52 cheshire
-Minor textual cleanup for clarity
+Revision 1.252 2007/03/23 22:59:58 cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
+Use kStandardTTL, not kHostNameTTL
-Revision 1.75 2004/09/02 03:48:47 cheshire
-<rdar://problem/3709039> Disable targeted unicast query support by default
-1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record
-2. New field AllowRemoteQuery in AuthRecord structure
-3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set
-4. mDNS.c only answers remote queries if AllowRemoteQuery is set
+Revision 1.251 2007/03/23 22:44:07 cheshire
+Instead of calling AbortUnlinkAndFree() haphazardly all over the place, make the handle* routines
+return an error code, and then request_callback() does all necessary cleanup in one place.
-Revision 1.74 2004/08/25 02:32:47 cheshire
-Minor cleanup: replace "®type[0]" with "regtype"
+Revision 1.250 2007/03/22 20:30:07 cheshire
+Remove pointless "if (request->ts != t_complete) ..." checks
-Revision 1.73 2004/08/25 02:30:40 cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.249 2007/03/22 20:13:27 cheshire
+Delete unused client_context field
-Revision 1.72 2004/08/14 03:22:42 cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.248 2007/03/22 20:03:37 cheshire
+Rename variables for clarity: instead of using variable rs for both request_state
+and reply_state, use req for request_state and rep for reply_state
-Revision 1.71 2004/08/11 04:21:21 rpantos
-Fix Windows build.
+Revision 1.247 2007/03/22 19:31:42 cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
+Add missing "model=" at start of DeviceInfo data
-Revision 1.70 2004/08/11 02:07:00 cheshire
-Remove "mDNS *globalInstance" parameter from udsserver_init()
-Move CheckForDuplicateRegistrations from daemon.c
-<rdar://problem/3501938> No warning when accidentally registering the same service multiple times using socket API
+Revision 1.246 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-Revision 1.69 2004/08/10 16:14:48 cheshire
-Fix debug builds (oops)
+Revision 1.245 2007/03/22 00:49:20 cheshire
+<rdar://problem/4848295> Advertise model information via Bonjour
-Revision 1.68 2004/08/10 06:24:56 cheshire
-Use types with precisely defined sizes for 'op' and 'reg_index', for better
-compatibility if the daemon and the client stub are built using different compilers
+Revision 1.244 2007/03/21 21:01:48 cheshire
+<rdar://problem/4789793> Leak on error path in regrecord_callback, uds_daemon.c
-Revision 1.67 2004/07/27 07:14:16 shersche
-make error socket non-blocking after call to connect()
+Revision 1.243 2007/03/21 19:01:57 cheshire
+<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-Revision 1.66 2004/07/13 21:24:25 rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.242 2007/03/21 18:51:21 cheshire
+<rdar://problem/4549320> Code in uds_daemon.c passes function name instead of type name to mallocL/freeL
-Revision 1.65 2004/06/26 03:17:14 shersche
-implement cross-platform strerror function
+Revision 1.241 2007/03/20 00:04:50 cheshire
+<rdar://problem/4837929> Should allow "udp" or "tcp" for protocol command-line arg
+Fix LogOperation("DNSServiceNATPortMappingCreate(...)") message to actually show client arguments
-Submitted by: herscher
+Revision 1.240 2007/03/16 23:25:35 cheshire
+<rdar://problem/5067001> NAT-PMP: Parameter validation not working correctly
-Revision 1.64 2004/06/25 00:26:27 rpantos
-Changes to fix the Posix build on Solaris.
+Revision 1.239 2007/03/10 02:29:36 cheshire
+Added comment about port_mapping_create_reply()
-Revision 1.63 2004/06/24 03:43:44 rpantos
-Fix previous checkin so it builds on Windows.
+Revision 1.238 2007/03/07 00:26:48 cheshire
+<rdar://problem/4426754> DNSServiceRemoveRecord log message should include record type
-Revision 1.62 2004/06/24 00:57:08 ksekar
-Replaced code acccidentally removed in checkin 1.59.
+Revision 1.237 2007/02/28 01:44:29 cheshire
+<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-Revision 1.61 2004/06/19 00:09:39 cheshire
-Remove unused strsep() implementation
+Revision 1.236 2007/02/14 01:58:19 cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-Revision 1.60 2004/06/18 19:10:00 cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
+Revision 1.235 2007/02/08 21:12:28 cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-Revision 1.59 2004/06/18 05:10:31 rpantos
-Changes to allow code to be used on Windows
+Revision 1.234 2007/02/06 19:06:49 cheshire
+<rdar://problem/3956518> Need to go native with launchd
-Revision 1.58 2004/06/15 03:54:08 cheshire
-Include mDNS_TimeNow(&mDNSStorage) in SIGINFO output
+Revision 1.233 2007/01/10 20:49:37 cheshire
+Remove unnecessary setting of q->Private fields
-Revision 1.57 2004/06/12 01:47:27 ksekar
-<rdar://problem/3690241>: BBEdit crashes when trying to check for newer version
-udsserver_idle compared time in ticks to interval in seconds.
+Revision 1.232 2007/01/09 00:03:23 cheshire
+Call udsserver_handle_configchange() once at the end of udsserver_init()
+to set up the automatic registration and browsing domains.
-Revision 1.56 2004/06/12 01:35:47 cheshire
-Changes for Windows compatibility
+Revision 1.231 2007/01/06 02:50:19 cheshire
+<rdar://problem/4632919> Instead of copying SRV and TXT record data, just store pointers to cache entities
-Revision 1.55 2004/06/05 00:04:27 cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
+Revision 1.230 2007/01/06 01:00:35 cheshire
+Improved SIGINFO output
-Revision 1.54 2004/06/01 22:22:52 ksekar
-<rdar://problem/3668635>: wide-area default registrations should be in
-.local too
+Revision 1.229 2007/01/05 08:30:56 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.53 2004/05/28 23:42:37 ksekar
-<rdar://problem/3258021>: Feature: DNS server->client notification on record changes (#7805)
+Revision 1.228 2007/01/05 08:09:05 cheshire
+Reorder code into functional sections, with "#pragma mark" headers
-Revision 1.52 2004/05/26 00:39:49 ksekar
-<rdar://problem/3667105>: wide-area DNS-SD servers don't appear in
-Finder
-Use local-only InterfaceID for GetDomains calls for sockets-API
+Revision 1.227 2007/01/05 07:04:24 cheshire
+Minor code tidying
-Revision 1.51 2004/05/18 23:51:27 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.226 2007/01/05 05:44:35 cheshire
+Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
+so that mDNSPosix embedded clients will compile again
-Revision 1.50 2004/05/14 16:39:47 ksekar
-Browse for iChat locally for now.
+Revision 1.225 2007/01/04 23:11:15 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-Revision 1.49 2004/05/13 21:33:52 ksekar
-Clean up non-local registration control via config file. Force iChat
-registrations to be local for now.
+Revision 1.224 2007/01/04 20:57:49 cheshire
+Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-Revision 1.48 2004/05/13 04:13:19 ksekar
-Updated SIGINFO handler for multi-domain browses
+Revision 1.223 2006/12/21 01:25:49 cheshire
+Tidy up SIGINFO state log
-Revision 1.47 2004/05/12 22:04:01 ksekar
-Implemented multi-domain browsing by default for uds_daemon.
+Revision 1.222 2006/12/21 00:15:22 cheshire
+Get rid of gmDNS macro; fixed a crash in udsserver_info()
-Revision 1.46 2004/05/06 18:42:58 ksekar
-General dns_sd.h API cleanup, including the following radars:
-<rdar://problem/3592068>: Remove flags with zero value
-<rdar://problem/3479569>: Passing in NULL causes a crash.
+Revision 1.221 2006/12/20 04:07:38 cheshire
+Remove uDNS_info substructure from AuthRecord_struct
-Revision 1.45 2004/03/12 08:49:28 cheshire
-#include <sys/socket.h>
+Revision 1.220 2006/12/19 22:49:25 cheshire
+Remove uDNS_info substructure from ServiceRecordSet_struct
-Revision 1.44 2004/02/25 01:25:27 ksekar
-<rdar://problem/3569212>: DNSServiceRegisterRecord flags not error-checked
+Revision 1.219 2006/12/14 03:02:38 cheshire
+<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-Revision 1.43 2004/02/24 01:46:40 cheshire
-Manually reinstate lost checkin 1.36
+Revision 1.218 2006/11/18 05:01:33 cheshire
+Preliminary support for unifying the uDNS and mDNS code,
+including caching of uDNS answers
-Revision 1.42 2004/02/05 19:39:29 cheshire
-Move creation of /var/run/mDNSResponder.pid to uds_daemon.c,
-so that all platforms get this functionality
+Revision 1.217 2006/11/15 19:27:53 mkrochma
+<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-Revision 1.41 2004/02/03 18:59:02 cheshire
-Change "char *domain" parameter for format_enumeration_reply to "const char *domain"
+Revision 1.216 2006/11/10 00:54:16 cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
-Revision 1.40 2004/01/28 03:41:00 cheshire
-<rdar://problem/3541946>: Need ability to do targeted queries as well as multicast queries
+Revision 1.215 2006/10/27 01:30:23 cheshire
+Need explicitly to set ReturnIntermed = mDNSfalse
-Revision 1.39 2004/01/25 00:03:21 cheshire
-Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
+Revision 1.214 2006/10/20 05:37:23 herscher
+Display question list information in udsserver_info()
-Revision 1.38 2004/01/19 19:51:46 cheshire
-Fix compiler error (mixed declarations and code) on some versions of Linux
+Revision 1.213 2006/10/05 03:54:31 herscher
+Remove embedded uDNS_info struct from DNSQuestion_struct
-Revision 1.37 2003/12/08 21:11:42 rpantos
-Changes necessary to support mDNSResponder on Linux.
+Revision 1.212 2006/09/30 01:22:35 cheshire
+Put back UTF-8 curly quotes in log messages
-Revision 1.36 2003/12/04 23:40:57 cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix some more code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+Revision 1.211 2006/09/27 00:44:55 herscher
+<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-Revision 1.35 2003/12/03 19:10:22 ksekar
-<rdar://problem/3498644>: malloc'd data not zero'd
+Revision 1.210 2006/09/26 01:52:41 herscher
+<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-Revision 1.34 2003/12/03 02:00:01 ksekar
-<rdar://problem/3498644>: malloc'd data not zero'd
+Revision 1.209 2006/09/21 21:34:09 cheshire
+<rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
-Revision 1.33 2003/11/22 01:18:46 ksekar
-<rdar://problem/3486646>: config change handler not called for dns-sd services
+Revision 1.208 2006/09/21 21:28:24 cheshire
+Code cleanup to make it consistent with daemon.c: change rename_on_memfree to renameonmemfree
-Revision 1.32 2003/11/20 21:46:12 ksekar
-<rdar://problem/3486635>: leak: DNSServiceRegisterRecord
+Revision 1.207 2006/09/15 21:20:16 cheshire
+Remove uDNS_info substructure from mDNS_struct
-Revision 1.31 2003/11/20 20:33:05 ksekar
-<rdar://problem/3486635>: leak: DNSServiceRegisterRecord
+Revision 1.206 2006/08/14 23:24:56 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.30 2003/11/20 02:10:55 ksekar
-<rdar://problem/3486643>: cleanup DNSServiceAdd/RemoveRecord
+Revision 1.205 2006/07/20 22:07:30 mkrochma
+<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
+More fixes for uninitialized variables
-Revision 1.29 2003/11/14 21:18:32 cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
+Revision 1.204 2006/07/15 02:01:33 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+Fix broken "empty string" browsing
-Revision 1.28 2003/11/08 22:18:29 cheshire
-<rdar://problem/3477870>: Don't need to show process ID in *every* mDNSResponder syslog message
+Revision 1.203 2006/07/07 01:09:13 cheshire
+<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
+Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-Revision 1.27 2003/11/05 22:44:57 ksekar
-<rdar://problem/3335230>: No bounds checking when reading data from client
-Reviewed by: Stuart Cheshire
+Revision 1.202 2006/07/05 22:00:10 cheshire
+Wide-area cleanup: Rename mDNSPlatformGetRegDomainList() to uDNS_GetDefaultRegDomainList()
-Revision 1.26 2003/10/23 17:51:04 ksekar
-<rdar://problem/3335216>: handle blocked clients more efficiently
-Changed gettimeofday() to mDNS_TimeNow(&mDNSStorage);
+Revision 1.201 2006/06/29 03:02:47 cheshire
+<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
-Revision 1.25 2003/10/22 23:37:49 ksekar
-<rdar://problem/3459141>: crash/hang in abort_client
+Revision 1.200 2006/06/28 08:56:26 cheshire
+Added "_op" to the end of the operation code enum values,
+to differentiate them from the routines with the same names
-Revision 1.24 2003/10/21 20:59:40 ksekar
-<rdar://problem/3335216>: handle blocked clients more efficiently
+Revision 1.199 2006/06/28 08:53:39 cheshire
+Added (commented out) debugging messages
-Revision 1.23 2003/09/23 02:12:43 cheshire
-Also include port number in list of services registered via new UDS API
+Revision 1.198 2006/06/27 20:16:07 cheshire
+Fix code layout
-Revision 1.22 2003/08/19 16:03:55 ksekar
-<rdar://problem/3380097>: ER: SIGINFO dump should include resolves started by DNSServiceQueryRecord
-Check termination_context for NULL before dereferencing.
+Revision 1.197 2006/05/18 01:32:35 cheshire
+<rdar://problem/4472706> iChat: Lost connection with Bonjour
+(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
-Revision 1.21 2003/08/19 05:39:43 cheshire
-<rdar://problem/3380097> SIGINFO dump should include resolves started by DNSServiceQueryRecord
+Revision 1.196 2006/05/05 07:07:13 cheshire
+<rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
-Revision 1.20 2003/08/16 03:39:01 cheshire
-<rdar://problem/3338440> InterfaceID -1 indicates "local only"
+Revision 1.195 2006/04/25 20:56:28 mkrochma
+Added comment about previous checkin
-Revision 1.19 2003/08/15 20:16:03 cheshire
-<rdar://problem/3366590> mDNSResponder takes too much RPRVT
-We want to avoid touching the rdata pages, so we don't page them in.
-1. RDLength was stored with the rdata, which meant touching the page just to find the length.
- Moved this from the RData to the ResourceRecord object.
-2. To avoid unnecessarily touching the rdata just to compare it,
- compute a hash of the rdata and store the hash in the ResourceRecord object.
+Revision 1.194 2006/04/25 18:29:36 mkrochma
+Workaround for warning: unused variable 'status' when building mDNSPosix
-Revision 1.18 2003/08/15 00:38:00 ksekar
-<rdar://problem/3377005>: Bug: buffer overrun when reading long rdata from client
+Revision 1.193 2006/03/19 17:14:38 cheshire
+<rdar://problem/4483117> Need faster purging of stale records
+read_rr_from_ipc_msg was not setting namehash and rdatahash
-Revision 1.17 2003/08/14 02:18:21 cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
+Revision 1.192 2006/03/18 20:58:32 cheshire
+Misplaced curly brace
-Revision 1.16 2003/08/13 23:58:52 ksekar
-<rdar://problem/3374911>: Bug: UDS Sub-type browsing works, but not sub-type registration
-Fixed pointer increment error, moved subtype reading for-loop for easier error bailout.
+Revision 1.191 2006/03/10 22:19:43 cheshire
+Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
-Revision 1.15 2003/08/13 17:30:33 ksekar
-<rdar://problem/3374671>: DNSServiceAddRecord doesn't work
-Fixed various problems with handling the AddRecord request and freeing the ExtraResourceRecords.
+Revision 1.190 2006/03/10 21:56:12 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
+when the TXT data changes, and then immediately afterwards a second callback with the new port number
+This change suppresses the first unneccessary (and confusing) callback
-Revision 1.14 2003/08/12 19:56:25 cheshire
-Update to APSL 2.0
+Revision 1.189 2006/01/06 00:56:31 cheshire
+<rdar://problem/4400573> Should remove PID file on exit
- */
+*/
#if defined(_WIN32)
#include <process.h>
-#define MDNS_LAZY_REGISTER_SEARCH_DOMAINS
-#define dnssd_strerror(X) win32_strerror(X)
-#define usleep(X) Sleep(((X)+999)/1000)
-static char * win32_strerror(int inErrorCode);
+#define dnssd_strerror(X) win32_strerror(X)
+#define usleep(X) Sleep(((X)+999)/1000)
+mDNSlocal char *win32_strerror(int inErrorCode)
+ {
+ static char buffer[1024];
+ DWORD n;
+ memset(buffer, 0, sizeof(buffer));
+ n = FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ (DWORD) inErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buffer,
+ sizeof(buffer),
+ NULL);
+ if (n > 0)
+ {
+ // Remove any trailing CR's or LF's since some messages have them.
+ while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1]))
+ buffer[--n] = '\0';
+ }
+ return buffer;
+ }
#else
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
-#define dnssd_strerror(X) strerror(X)
+#define dnssd_strerror(X) strerror(X)
#endif
#include <stdlib.h>
#include <stdio.h>
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
+#include "uDNS.h"
#include "uds_daemon.h"
-#include "dns_sd.h"
-#include "dnssd_ipc.h"
-// Apple specific configuration functionality, not required for other platforms
-#ifdef __MACOSX__
+// Apple-specific functionality, not required for other platforms
+#if APPLE_OSX_mDNSResponder
#include <sys/ucred.h>
-#ifndef LOCAL_PEERCRED
-#define LOCAL_PEERCRED 0x001 /* retrieve peer credentials */
-#endif // LOCAL_PEERCRED
-#endif //__MACOSX__
-
-#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
-extern mStatus dDNS_RegisterSearchDomains( mDNS * const m );
+#ifndef PID_FILE
+#define PID_FILE ""
+#endif
#endif
-// Types and Data Structures
-// ----------------------------------------------------------------------
+// User IDs 0-500 are system-wide processes, not actual users in the usual sense
+// User IDs for real user accounts start at 501 and count up from there
+#define SystemUID(X) ((X) <= 500)
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Types and Data Structures
+#endif
typedef enum
- {
- t_uninitialized,
- t_morecoming,
- t_complete,
- t_error,
- t_terminated
- } transfer_state;
+ {
+ t_uninitialized,
+ t_morecoming,
+ t_complete,
+ t_error,
+ t_terminated
+ } transfer_state;
+
+typedef struct request_state request_state;
-typedef void (*req_termination_fn)(void *);
+typedef void (*req_termination_fn)(request_state *request);
typedef struct registered_record_entry
- {
- uint32_t key;
- AuthRecord *rr;
- struct registered_record_entry *next;
- client_context_t client_context;
- struct request_state *rstate;
- } registered_record_entry;
+ {
+ struct registered_record_entry *next;
+ mDNSu32 key;
+ AuthRecord *rr; // Variable-sized AuthRecord
+ client_context_t client_context;
+ request_state *request;
+ } registered_record_entry;
// A single registered service: ServiceRecordSet + bookkeeping
// Note that we duplicate some fields from parent service_info object
// to facilitate cleanup, when instances and parent may be deallocated at different times.
typedef struct service_instance
- {
- struct service_instance *next;
- mDNSBool autoname; // Set if this name is tied to the Computer Name
- mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
- mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
- mDNSBool rename_on_memfree; // Set on config change when we deregister original name
- domainlabel name;
- domainname domain;
- mDNSBool default_local; // is this the "local." from an empty-string registration?
- struct request_state *request;
- dnssd_sock_t sd;
- AuthRecord *subtypes;
- ServiceRecordSet srs; // note - must be last field in struct
- } service_instance;
-
-// A client-created service. May reference several service_info objects if default
-// settings cause registration in multiple domains.
-typedef struct
{
- uint16_t txtlen;
- void *txtdata;
- mDNSIPPort port;
- domainlabel name;
- char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
- domainname type;
- mDNSBool default_domain;
- domainname host;
- mDNSBool autoname; // Set if this name is tied to the Computer Name
- mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
- mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
- int num_subtypes;
- mDNSInterfaceID InterfaceID;
- service_instance *instances;
- struct request_state *request;
- } service_info;
+ struct service_instance *next;
+ request_state *request;
+ dnssd_sock_t sd;
+ AuthRecord *subtypes;
+ mDNSBool renameonmemfree; // Set on config change when we deregister original name
+ mDNSBool clientnotified; // Has client been notified of successful registration yet?
+ mDNSBool default_local; // is this the "local." from an empty-string registration?
+ domainname domain;
+ ServiceRecordSet srs; // note - must be last field in struct
+ } service_instance;
// for multi-domain default browsing
typedef struct browser_t
{
- DNSQuestion q;
- domainname domain;
- struct browser_t *next;
+ struct browser_t *next;
+ domainname domain;
+ DNSQuestion q;
} browser_t;
-// parent struct for browser instances: list pointer plus metadata
-typedef struct
+struct request_state
{
- mDNSBool default_domain;
- mDNSBool ForceMCast;
- domainname regtype;
- mDNSInterfaceID interface_id;
- struct request_state *rstate;
- browser_t *browsers;
- } browser_info_t;
-
-typedef struct
- {
- mStatus err; // Note: This field is in NETWORK byte order
- int nwritten;
- dnssd_sock_t sd;
- } undelivered_error_t;
-
-typedef struct request_state
- {
- // connection structures
- dnssd_sock_t sd;
-
- // state of read (in case message is read over several recv() calls)
- transfer_state ts;
- uint32_t hdr_bytes; // bytes of header already read
- ipc_msg_hdr hdr;
- uint32_t data_bytes; // bytes of message data already read
- char *msgbuf; // pointer to data storage to pass to free()
- char *msgdata; // pointer to data to be read from (may be modified)
- int bufsize; // size of data storage
-
- // reply, termination, error, and client context info
- int no_reply; // don't send asynchronous replies to client
- int time_blocked; // record time of a blocked client
- void *client_context; // don't touch this - pointer only valid in client's addr space
- struct reply_state *replies; // corresponding (active) reply list
- undelivered_error_t *u_err;
- void *termination_context;
- req_termination_fn terminate;
-
- //!!!KRS toss these pointers in a union
- // registration context associated with this request (null if not applicable)
- registered_record_entry *reg_recs; // muliple registrations for a connection-oriented request
- service_info *service_registration;
- browser_info_t *browser_info;
- struct request_state *next;
- } request_state;
+ request_state *next;
+ request_state *primary; // If this operation is on a shared socket, pointer to
+ // primary request_state for the original DNSServiceConnect() operation
+ dnssd_sock_t sd;
+ dnssd_sock_t errsd;
+ mDNSu32 uid;
+
+ // NOTE: On a shared connection these fields in the primary structure, including hdr, are re-used
+ // for each new request. This is because, until we've read the ipc_msg_hdr to find out what the
+ // operation is, we don't know if we're going to need to allocate a new request_state or not.
+ transfer_state ts;
+ mDNSu32 hdr_bytes; // bytes of header already read
+ ipc_msg_hdr hdr;
+ mDNSu32 data_bytes; // bytes of message data already read
+ char *msgbuf; // pointer to data storage to pass to free()
+ char *msgptr; // pointer to data to be read from (may be modified)
+ char *msgend; // pointer to byte after last byte of message
+
+ // reply, termination, error, and client context info
+ int no_reply; // don't send asynchronous replies to client
+ int time_blocked; // record time of a blocked client
+ struct reply_state *replies; // corresponding (active) reply list
+ req_termination_fn terminate;
+
+ union
+ {
+ registered_record_entry *reg_recs; // list of registrations for a connection-oriented request
+ struct
+ {
+ mDNSInterfaceID interface_id;
+ mDNSBool default_domain;
+ mDNSBool ForceMCast;
+ domainname regtype;
+ browser_t *browsers;
+ } browser;
+ struct
+ {
+ mDNSInterfaceID InterfaceID;
+ mDNSu16 txtlen;
+ void *txtdata;
+ mDNSIPPort port;
+ domainlabel name;
+ char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
+ domainname type;
+ mDNSBool default_domain;
+ domainname host;
+ mDNSBool autoname; // Set if this name is tied to the Computer Name
+ mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
+ mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
+ int num_subtypes;
+ service_instance *instances;
+ } servicereg;
+ struct
+ {
+ mDNSInterfaceID interface_id;
+ mDNSu32 flags;
+ mDNSu32 protocol;
+ DNSQuestion q4;
+ DNSQuestion q6;
+ } addrinfo;
+ struct
+ {
+ mDNSIPPort ReqExt; // External port we originally requested, for logging purposes
+ NATTraversalInfo NATinfo;
+ } pm;
+ struct
+ {
+ DNSQuestion q_all;
+ DNSQuestion q_default;
+ } enumeration;
+ struct
+ {
+ DNSQuestion q;
+ } queryrecord;
+ struct
+ {
+ DNSQuestion qtxt;
+ DNSQuestion qsrv;
+ const ResourceRecord *txt;
+ const ResourceRecord *srv;
+ } resolve;
+ ;
+ } u;
+ };
// struct physically sits between ipc message header and call-specific fields in the message buffer
typedef struct
- {
- DNSServiceFlags flags; // Note: This field is in NETWORK byte order
- uint32_t ifi; // Note: This field is in NETWORK byte order
- DNSServiceErrorType error; // Note: This field is in NETWORK byte order
- } reply_hdr;
+ {
+ DNSServiceFlags flags; // Note: This field is in NETWORK byte order
+ mDNSu32 ifi; // Note: This field is in NETWORK byte order
+ DNSServiceErrorType error; // Note: This field is in NETWORK byte order
+ } reply_hdr;
typedef struct reply_state
- {
- // state of the transmission
- dnssd_sock_t sd;
- transfer_state ts;
- uint32_t nwriten;
- uint32_t len;
- // context of the reply
- struct request_state *request; // the request that this answers
- struct reply_state *next; // if there are multiple unsent replies
- // pointer into message buffer - allows fields to be changed after message is formatted
- ipc_msg_hdr *mhdr;
- reply_hdr *rhdr;
- char *sdata; // pointer to start of call-specific data
- // pointer to malloc'd buffer
- char *msgbuf;
- } reply_state;
-
-// domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
-// structures to handle callbacks
-typedef struct
- {
- DNSQuestion question;
- mDNS_DomainType type;
- request_state *rstate;
- } domain_enum_t;
-
-typedef struct
- {
- domain_enum_t *all;
- domain_enum_t *def;
- request_state *rstate;
- } enum_termination_t;
-
-typedef struct
- {
- request_state *rstate;
- DNSQuestion qtxt;
- DNSQuestion qsrv;
- // const ResourceRecord *txt;
- // const ResourceRecord *srv;
- mDNSBool srv;
- mDNSBool txt;
- rdataSRV srvdata;
- mDNSu16 txtlen;
- mDNSu8 txtdata[AbsoluteMaxDNSMessageData];
- } resolve_termination_t;
-
-#ifdef _HAVE_SETDOMAIN_SUPPORT_
-typedef struct default_browse_list_t
- {
- struct default_browse_list_t *next;
- uid_t uid;
- AuthRecord ptr_rec;
- } default_browse_list_t;
-
-static default_browse_list_t *default_browse_list = NULL;
-#endif // _HAVE_SETDOMAIN_SUPPORT_
+ {
+ dnssd_sock_t sd;
+ transfer_state ts;
+ mDNSu32 nwriten;
+ mDNSu32 len;
+ request_state *request; // the request that this answers
+ struct reply_state *next; // if there are multiple unsent replies
+ char *msgbuf; // pointer to malloc'd buffer
+ ipc_msg_hdr *mhdr; // pointer into message buffer - allows fields to be changed after message is formatted
+ reply_hdr *rhdr;
+ char *sdata; // pointer to start of call-specific data
+ } reply_state;
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Globals
+#endif
// globals
mDNSexport mDNS mDNSStorage;
-#define gmDNS (&mDNSStorage)
-
-static dnssd_sock_t listenfd = dnssd_InvalidSocket;
-static request_state * all_requests = NULL;
-
-#define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond // try to send data to a blocked client for 60 seconds before
- // terminating connection
-#define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
- // n get_string() calls w/o buffer overrun
-// private function prototypes
-mDNSlocal void connect_callback(void *info);
-mDNSlocal int read_msg(request_state *rs);
-mDNSlocal int send_msg(reply_state *rs);
-mDNSlocal void abort_request(request_state *rs);
-mDNSlocal void request_callback(void *info);
-mDNSlocal void handle_resolve_request(request_state *rstate);
-mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-mDNSlocal void question_termination_callback(void *context);
-mDNSlocal void handle_browse_request(request_state *request);
-mDNSlocal void browse_termination_callback(void *context);
-mDNSlocal void handle_regservice_request(request_state *request);
-mDNSlocal void regservice_termination_callback(void *context);
-mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-mDNSlocal mStatus handle_add_request(request_state *rstate);
-mDNSlocal mStatus handle_update_request(request_state *rstate);
-mDNSlocal void append_reply(request_state *req, reply_state *rep);
-mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
-mDNSlocal void enum_termination_callback(void *context);
-mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-mDNSlocal void handle_query_request(request_state *rstate);
-mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
-mDNSlocal void handle_enum_request(request_state *rstate);
-mDNSlocal mStatus handle_regrecord_request(request_state *rstate);
-mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
-mDNSlocal void connected_registration_termination(void *context);
-mDNSlocal void handle_reconfirm_request(request_state *rstate);
-mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
-mDNSlocal mStatus handle_removerecord_request(request_state *rstate);
-mDNSlocal void reset_connected_rstate(request_state *rstate);
-mDNSlocal int deliver_error(request_state *rstate, mStatus err);
-mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
-mDNSlocal transfer_state send_undelivered_error(request_state *rs);
-mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
-mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
-mDNSlocal void my_perror(char *errmsg);
-mDNSlocal void unlink_request(request_state *rs);
-mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-mDNSlocal void resolve_termination_callback(void *context);
-mDNSlocal int validate_message(request_state *rstate);
-mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv);
-mDNSlocal mStatus remove_record(request_state *rstate);
-mDNSlocal void free_service_instance(service_instance *srv);
-mDNSlocal uint32_t dnssd_htonl(uint32_t l);
-mDNSlocal void handle_setdomain_request(request_state *rstate);
+mDNSexport const char ProgramName[] = "mDNSResponder";
+
+static dnssd_sock_t listenfd = dnssd_InvalidSocket;
+static request_state *all_requests = NULL;
+static DNameListElem *SCPrefBrowseDomains; // List of automatic browsing domains read from SCPreferences for "empty string" browsing
+static ARListElem *LocalDomainEnumRecords; // List of locally-generated PTR records to augment those we learn from the network
+mDNSexport DNameListElem *AutoBrowseDomains; // List created from those local-only PTR records plus records we get from the network
+
+mDNSexport DNameListElem *AutoRegistrationDomains; // Domains where we automatically register for empty-string registrations
+
+#define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
+ // n get_string() calls w/o buffer overrun
// initialization, setup/teardown functions
// If a platform specifies its own PID file name, we use that
#define PID_FILE "/var/run/mDNSResponder.pid"
#endif
-mDNSlocal void LogClientInfo(request_state *req)
- {
- void *t = req->termination_context;
- if (t)
- {
- if (req->terminate == regservice_termination_callback)
- {
- service_instance *ptr;
- for (ptr = ((service_info *)t)->instances; ptr; ptr = ptr->next)
- LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
- }
- else if (req->terminate == browse_termination_callback)
- {
- browser_t *blist;
- for (blist = req->browser_info->browsers; blist; blist = blist->next)
- LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req->sd, blist->q.qname.c);
- }
- else if (req->terminate == resolve_termination_callback)
- LogMsgNoIdent("%3d: DNSServiceResolve %##s", req->sd, ((resolve_termination_t *)t)->qsrv.qname.c);
- else if (req->terminate == question_termination_callback)
- LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s", req->sd, ((DNSQuestion *) t)->qname.c);
- else if (req->terminate == enum_termination_callback)
- LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, ((enum_termination_t *) t)->all->question.qname.c);
- }
- }
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Utility Functions
+#endif
mDNSlocal void FatalError(char *errmsg)
{
abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
}
-int udsserver_init(void)
+mDNSlocal mDNSu32 dnssd_htonl(mDNSu32 l)
{
- dnssd_sockaddr_t laddr;
- int ret;
-#if defined(_WIN32)
- u_long opt = 1;
-#endif
+ mDNSu32 ret;
+ char *data = (char*) &ret;
+ put_uint32(l, &data);
+ return ret;
+ }
- // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
- if (PID_FILE[0])
+// hack to search-replace perror's to LogMsg's
+mDNSlocal void my_perror(char *errmsg)
+ {
+ LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
+ }
+
+mDNSlocal void abort_request(request_state *req)
+ {
+ // First stop whatever mDNSCore operation we were doing
+ if (req->terminate) req->terminate(req);
+
+ // Now, if this request_state is not subbordinate to some other primary, close file descriptor and discard replies
+ if (!req->primary)
{
- FILE *fp = fopen(PID_FILE, "w");
- if (fp != NULL)
+ if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
+ else LogOperation("%3d: Removing FD", req->sd);
+ udsSupportRemoveFDFromEventLoop(req->sd); // Note: This also closes file descriptor req->sd for us
+ if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
+
+ while (req->replies) // free pending replies
{
- fprintf(fp, "%d\n", getpid());
- fclose(fp);
+ reply_state *ptr = req->replies;
+ req->replies = req->replies->next;
+ if (ptr->msgbuf) freeL("reply_state msgbuf (abort)", ptr->msgbuf);
+ freeL("reply_state (abort)", ptr);
}
}
- if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
- {
- my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
- goto error;
- }
+// Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+ // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
+ // for detecting when the memory for an object is inadvertently freed while the object is still on some list
+ req->sd = -2;
+#else
+ req->sd = dnssd_InvalidSocket;
+#endif
+ }
+
+mDNSlocal void AbortUnlinkAndFree(request_state *req)
+ {
+ request_state **p = &all_requests;
+ abort_request(req);
+ while (*p && *p != req) p=&(*p)->next;
+ if (*p) { *p = req->next; freeL("request_state/AbortUnlinkAndFree", req); }
+ }
- bzero(&laddr, sizeof(laddr));
+mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, request_state *const request)
+ {
+ reply_state *reply;
+ int totallen = (int) (datalen + sizeof(ipc_msg_hdr));
- #if defined(USE_TCP_LOOPBACK)
+ if ((unsigned)datalen < sizeof(reply_hdr))
{
- laddr.sin_family = AF_INET;
- laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
- laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
- ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
- if (ret < 0)
- {
- my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
- goto error;
- }
+ LogMsg("ERROR: create_reply - data length less than lenght of required fields");
+ return NULL;
}
- #else
+
+ reply = mallocL("reply_state", sizeof(reply_state));
+ if (!reply) FatalError("ERROR: malloc");
+ mDNSPlatformMemZero(reply, sizeof(reply_state));
+ reply->ts = t_morecoming;
+ reply->sd = request->sd;
+ reply->request = request;
+ reply->len = totallen;
+ reply->msgbuf = mallocL("reply_state msgbuf", totallen);
+ if (!reply->msgbuf) FatalError("ERROR: malloc");
+ mDNSPlatformMemZero(reply->msgbuf, totallen);
+ reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
+ reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
+ reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
+ reply->mhdr->version = VERSION;
+ reply->mhdr->datalen = datalen;
+ reply->mhdr->ipc_flags = 0;
+ reply->mhdr->op = op;
+ reply->mhdr->client_context = request->hdr.client_context;
+ reply->mhdr->reg_index = 0;
+ return reply;
+ }
+
+// Append a reply to the list in a request object
+// If our request is sharing a connection, then we append our reply_state onto the primary's list
+mDNSlocal void append_reply(request_state *req, reply_state *rep)
+ {
+ request_state *r = req->primary ? req->primary : req;
+ reply_state **ptr = &r->replies;
+ while (*ptr) ptr = &(*ptr)->next;
+ *ptr = rep;
+ rep->next = NULL;
+ }
+
+// Generates a response message giving name, type, domain, plus interface index,
+// suitable for a browse result or service registration result.
+// On successful completion rep is set to point to a malloc'd reply_state struct
+mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const mDNSInterfaceID id,
+ request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err)
+ {
+ domainlabel name;
+ domainname type, dom;
+ *rep = NULL;
+ if (!DeconstructServiceName(servicename, &name, &type, &dom))
+ return kDNSServiceErr_Invalid;
+ else
{
- mode_t mask = umask(0);
- unlink(MDNS_UDS_SERVERPATH); //OK if this fails
- laddr.sun_family = AF_LOCAL;
- #ifndef NOT_HAVE_SA_LEN
- // According to Stevens (section 3.2), there is no portable way to
- // determine whether sa_len is defined on a particular platform.
- laddr.sun_len = sizeof(struct sockaddr_un);
- #endif
- strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
- ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
- umask(mask);
- if (ret < 0)
- {
- my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
- goto error;
- }
+ char namestr[MAX_DOMAIN_LABEL+1];
+ char typestr[MAX_ESCAPED_DOMAIN_NAME];
+ char domstr [MAX_ESCAPED_DOMAIN_NAME];
+ int len;
+ char *data;
+
+ ConvertDomainLabelToCString_unescaped(&name, namestr);
+ ConvertDomainNameToCString(&type, typestr);
+ ConvertDomainNameToCString(&dom, domstr);
+
+ // Calculate reply data length
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(mDNSu32); // if index
+ len += sizeof(DNSServiceErrorType);
+ len += (int) (strlen(namestr) + 1);
+ len += (int) (strlen(typestr) + 1);
+ len += (int) (strlen(domstr) + 1);
+
+ // Build reply header
+ *rep = create_reply(op, len, request);
+ (*rep)->rhdr->flags = dnssd_htonl(flags);
+ (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id));
+ (*rep)->rhdr->error = dnssd_htonl(err);
+
+ // Build reply body
+ data = (*rep)->sdata;
+ put_string(namestr, &data);
+ put_string(typestr, &data);
+ put_string(domstr, &data);
+
+ return mStatus_NoError;
}
- #endif
+ }
- #if defined(_WIN32)
- //
- // SEH: do we even need to do this on windows? this socket
- // will be given to WSAEventSelect which will automatically
- // set it to non-blocking
- //
- if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
- #else
- if (fcntl(listenfd, F_SETFL, O_NONBLOCK) != 0)
- #endif
+// Returns a resource record (allocated w/ malloc) containing the data found in an IPC message
+// Data must be in the following format: flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional) ttl
+// (ttl only extracted/set if ttl argument is non-zero). Returns NULL for a bad-parameter error
+mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, int validate_flags)
+ {
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ char name[256];
+ int str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name));
+ mDNSu16 type = get_uint16(&request->msgptr, request->msgend);
+ mDNSu16 class = get_uint16(&request->msgptr, request->msgend);
+ mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
+ char *rdata = get_rdata(&request->msgptr, request->msgend, rdlen);
+ mDNSu32 ttl = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0;
+ int storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
+ AuthRecord *rr;
+
+ if (str_err) { LogMsg("ERROR: read_rr_from_ipc_msg - get_string"); return NULL; }
+
+ if (!request->msgptr) { LogMsg("Error reading Resource Record from client"); return NULL; }
+
+ if (validate_flags &&
+ !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
+ !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
{
- my_perror("ERROR: could not set listen socket to non-blocking mode");
- goto error;
+ LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
+ return NULL;
}
- if (listen(listenfd, LISTENQ) != 0)
+ rr = mallocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
+ if (!rr) FatalError("ERROR: malloc");
+ mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex),
+ type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
+
+ if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
{
- my_perror("ERROR: could not listen on listen socket");
- goto error;
+ LogMsg("ERROR: bad name: %s", name);
+ freeL("AuthRecord/read_rr_from_ipc_msg", rr);
+ return NULL;
}
- if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
- {
- my_perror("ERROR: could not add listen socket to event loop");
- goto error;
- }
+ if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
+ rr->resrec.rrclass = class;
+ rr->resrec.rdlength = rdlen;
+ rr->resrec.rdata->MaxRDLength = rdlen;
+ mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlen);
+ if (GetTTL) rr->resrec.rroriginalttl = ttl;
+ rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
+ SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
+ return rr;
+ }
-#if !defined(PLATFORM_NO_RLIMIT)
+mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
{
- // Set maximum number of open file descriptors
- #define MIN_OPENFILES 10240
- struct rlimit maxfds, newfds;
-
- // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
- // you have to get and set rlimits once before getrlimit will return sensible values
- if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
- if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+ domainlabel n;
+ domainname d, t;
- if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
- newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
- newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
- if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
- if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+ if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
+ if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
+ if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
+ if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
+ return 0;
+ }
- if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
- debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
- debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
+mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len)
+ {
+ int n = send(s, ptr, len, 0);
+ // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a small write for us
+ // (four bytes for a typical error code return, 12 bytes for DNSServiceGetProperty(DaemonVersion)).
+ // If it does fail, we don't attempt to handle this failure, but we do log it so we know something is wrong.
+ if (n < len)
+ LogMsg("ERROR: send_all(%d) wrote %d of %d errno %d %s",
+ s, n, len, dnssd_errno(), dnssd_strerror(dnssd_errno()));
}
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceRegister
#endif
-
- return 0;
-
-error:
- my_perror("ERROR: udsserver_init");
- return -1;
- }
+mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
+ {
+ ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
+ (void)m; //unused
+
+ if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
+
+ LogOperation(" FreeExtraRR %s", RRDisplayString(m, &rr->resrec));
+
+ if (rr->resrec.rdata != &rr->rdatastorage)
+ freeL("Extra RData", rr->resrec.rdata);
+ freeL("ExtraResourceRecord/FreeExtraRR", extra);
+ }
+
+mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
+ {
+ ExtraResourceRecord *e = srv->srs.Extras, *tmp;
+
+ // clear pointers from parent struct
+ if (srv->request)
+ {
+ service_instance **p = &srv->request->u.servicereg.instances;
+ while (*p)
+ {
+ if (*p == srv) { *p = (*p)->next; break; }
+ p = &(*p)->next;
+ }
+ }
+
+ while (e)
+ {
+ e->r.RecordContext = e;
+ tmp = e;
+ e = e->next;
+ FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
+ }
+
+ if (srv->srs.RR_TXT.resrec.rdata != &srv->srs.RR_TXT.rdatastorage)
+ freeL("TXT RData", srv->srs.RR_TXT.resrec.rdata);
+
+ if (srv->subtypes) { freeL("ServiceSubTypes", srv->subtypes); srv->subtypes = NULL; }
+ freeL("service_instance", srv);
+ }
+
+// Count how many other service records we have locally with the same name, but different rdata.
+// For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
+// the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
+mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
+ {
+ int count = 0;
+ ResourceRecord *r = &srs->RR_SRV.resrec;
+ AuthRecord *rr;
+ ServiceRecordSet *s;
+
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
+ count++;
+
+ for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
+ if (s->state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
+ count++;
+
+ verbosedebugf("%d peer registrations for %##s", count, r->name->c);
+ return(count);
+ }
+
+mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
+ {
+ int count = 0;
+ AuthRecord *rr;
+ for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.rrtype == kDNSType_SRV &&
+ mDNSSameIPPort(rr->resrec.rdata->u.srv.port, port) &&
+ SameDomainName(rr->resrec.name, srv))
+ count++;
+ return(count);
+ }
+
+mDNSlocal void SendServiceRemovalNotification(ServiceRecordSet *const srs)
+ {
+ reply_state *rep;
+ service_instance *instance = srs->ServiceContext;
+ if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, 0, mStatus_NoError) != mStatus_NoError)
+ LogMsg("%3d: SendServiceRemovalNotification: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c);
+ else { append_reply(instance->request, rep); instance->clientnotified = mDNSfalse; }
+ }
+
+// service registration callback performs three duties - frees memory for deregistered services,
+// handles name conflicts, and delivers completed registration information to the client (via
+// process_service_registraion())
+mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
+ {
+ mStatus err;
+ mDNSBool SuppressError = mDNSfalse;
+ service_instance *instance = srs->ServiceContext;
+ reply_state *rep;
+ (void)m; // Unused
+ if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
+ if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
+
+ // don't send errors up to client for wide-area, empty-string registrations
+ if (instance->request &&
+ instance->request->u.servicereg.default_domain &&
+ !instance->default_local)
+ SuppressError = mDNStrue;
+
+ if (result == mStatus_NoError)
+ LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+ else if (result == mStatus_MemFree)
+ LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+ else if (result == mStatus_NameConflict)
+ LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+ else
+ LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
+
+ if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
+
+ if (result == mStatus_NoError)
+ {
+ if (instance->request->u.servicereg.allowremotequery)
+ {
+ ExtraResourceRecord *e;
+ srs->RR_ADV.AllowRemoteQuery = mDNStrue;
+ srs->RR_PTR.AllowRemoteQuery = mDNStrue;
+ srs->RR_SRV.AllowRemoteQuery = mDNStrue;
+ srs->RR_TXT.AllowRemoteQuery = mDNStrue;
+ for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
+ }
+
+ if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
+ LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c);
+ else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+
+ if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
+ RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
+ }
+ else if (result == mStatus_MemFree)
+ {
+ if (instance->request && instance->renameonmemfree)
+ {
+ instance->renameonmemfree = 0;
+ err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
+ if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
+ // error should never happen - safest to log and continue
+ }
+ else
+ unlink_and_free_service_instance(instance);
+ }
+ else if (result == mStatus_NameConflict)
+ {
+ if (instance->request->u.servicereg.autorename)
+ {
+ if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
+ {
+ // On conflict for an autoname service, rename and reregister *all* autoname services
+ IncrementLabelSuffix(&m->nicelabel, mDNStrue);
+ m->MainCallback(m, mStatus_ConfigChanged); // will call back into udsserver_handle_configchange()
+ }
+ else // On conflict for a non-autoname service, rename and reregister just that one service
+ {
+ if (instance->clientnotified) SendServiceRemovalNotification(srs);
+ mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
+ }
+ }
+ else
+ {
+ if (!SuppressError)
+ {
+ if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
+ LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c);
+ else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+ }
+ unlink_and_free_service_instance(instance);
+ }
+ }
+ else
+ {
+ if (result != mStatus_NATTraversal)
+ LogMsg("regservice_callback: Error %d%s for %s", result, SuppressError ? " (suppressed)" : "", ARDisplayString(m, &srs->RR_SRV));
+ if (!SuppressError)
+ {
+ if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
+ LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c);
+ else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+ }
+ unlink_and_free_service_instance(instance);
+ }
+ }
+
+mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
+ {
+ (void)m; // Unused
+ if (!rr->RecordContext) // parent struct already freed by termination callback
+ {
+ if (result == mStatus_NoError)
+ LogMsg("Error: regrecord_callback: successful registration of orphaned record");
+ else
+ {
+ if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
+ freeL("AuthRecord/regrecord_callback", rr);
+ }
+ }
+ else
+ {
+ registered_record_entry *re = rr->RecordContext;
+ request_state *request = re->request;
+ int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
+ reply_state *reply = create_reply(reg_record_reply_op, len, request);
+ reply->mhdr->client_context = re->client_context;
+ reply->rhdr->flags = dnssd_htonl(0);
+ reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID));
+ reply->rhdr->error = dnssd_htonl(result);
+
+ LogOperation("%3d: DNSServiceRegisterRecord(%u) result %d", request->sd, request->hdr.reg_index, result);
+ if (result)
+ {
+ // unlink from list, free memory
+ registered_record_entry **ptr = &request->u.reg_recs;
+ while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
+ if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
+ *ptr = (*ptr)->next;
+ freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
+ freeL("registered_record_entry regrecord_callback", re);
+ }
+ append_reply(request, reply);
+ }
+ }
+
+mDNSlocal void connection_termination(request_state *request)
+ {
+ request_state **req = &all_requests;
+ while (*req)
+ {
+ if ((*req)->primary == request)
+ {
+ // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
+ request_state *tmp = *req;
+ abort_request(tmp);
+ *req = tmp->next;
+ freeL("request_state/connection_termination", tmp);
+ }
+ else
+ req = &(*req)->next;
+ }
+
+ while (request->u.reg_recs)
+ {
+ registered_record_entry *ptr = request->u.reg_recs;
+ request->u.reg_recs = request->u.reg_recs->next;
+ ptr->rr->RecordContext = NULL;
+ mDNS_Deregister(&mDNSStorage, ptr->rr); // Will free ptr->rr for us
+ freeL("registered_record_entry/connection_termination", ptr);
+ }
+ }
+
+mDNSlocal void handle_cancel_request(request_state *request)
+ {
+ request_state **req = &all_requests;
+ LogOperation("%3d: Cancel %X%08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
+ while (*req)
+ {
+ if ((*req)->primary == request &&
+ (*req)->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] &&
+ (*req)->hdr.client_context.u32[1] == request->hdr.client_context.u32[1])
+ {
+ // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
+ request_state *tmp = *req;
+ abort_request(tmp);
+ *req = tmp->next;
+ freeL("request_state/handle_cancel_request", tmp);
+ }
+ else
+ req = &(*req)->next;
+ }
+ }
+
+mDNSlocal mStatus handle_regrecord_request(request_state *request)
+ {
+ mStatus err = mStatus_BadParamErr;
+ AuthRecord *rr = read_rr_from_ipc_msg(request, 1, 1);
+ if (rr)
+ {
+ // allocate registration entry, link into list
+ registered_record_entry *re = mallocL("registered_record_entry", sizeof(registered_record_entry));
+ if (!re) FatalError("ERROR: malloc");
+ re->key = request->hdr.reg_index;
+ re->rr = rr;
+ re->request = request;
+ re->client_context = request->hdr.client_context;
+ rr->RecordContext = re;
+ rr->RecordCallback = regrecord_callback;
+ re->next = request->u.reg_recs;
+ request->u.reg_recs = re;
+
+ if (rr->resrec.rroriginalttl == 0)
+ rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
+
+ LogOperation("%3d: DNSServiceRegisterRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &rr->resrec));
+ err = mDNS_Register(&mDNSStorage, rr);
+ }
+ return(err);
+ }
+
+mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, char *rdata, mDNSu32 ttl)
+ {
+ ServiceRecordSet *srs = &instance->srs;
+ mStatus result;
+ int size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
+ ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
+ if (!extra) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
+
+ mDNSPlatformMemZero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
+ extra->r.resrec.rrtype = rrtype;
+ extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
+ extra->r.resrec.rdlength = rdlen;
+ mDNSPlatformMemCopy(&extra->r.rdatastorage.u.data, rdata, rdlen);
+
+ result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl);
+ if (result) { freeL("ExtraResourceRecord/add_record_to_service", extra); return result; }
+
+ extra->ClientID = request->hdr.reg_index;
+ return result;
+ }
+
+mDNSlocal mStatus handle_add_request(request_state *request)
+ {
+ service_instance *i;
+ mStatus result = mStatus_UnknownErr;
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ mDNSu16 rrtype = get_uint16(&request->msgptr, request->msgend);
+ mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
+ char *rdata = get_rdata(&request->msgptr, request->msgend, rdlen);
+ mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend);
+ if (!ttl) ttl = DefaultTTLforRRType(rrtype);
+ (void)flags; // Unused
+
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ LogOperation("%3d: DNSServiceAddRecord(%##s, %s, %d)", request->sd,
+ (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen);
+
+ for (i = request->u.servicereg.instances; i; i = i->next)
+ {
+ result = add_record_to_service(request, i, rrtype, rdlen, rdata, ttl);
+ if (result && i->default_local) break;
+ else result = mStatus_NoError; // suppress non-local default errors
+ }
+
+ return(result);
+ }
+
+mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
+ {
+ (void)m; // Unused
+ if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
+ }
+
+mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, char *rdata, mDNSu32 ttl)
+ {
+ int rdsize;
+ RData *newrd;
+ mStatus result;
+
+ if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
+ else rdsize = sizeof(RDataBody);
+ newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
+ if (!newrd) FatalError("ERROR: malloc");
+ newrd->MaxRDLength = (mDNSu16) rdsize;
+ mDNSPlatformMemCopy(&newrd->u, rdata, rdlen);
+
+ // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
+ // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
+ // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
+ if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
+
+ result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
+ if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("RData/update_record", newrd); }
+ return result;
+ }
+
+mDNSlocal mStatus handle_update_request(request_state *request)
+ {
+ mStatus result = mStatus_BadReferenceErr;
+ service_instance *i;
+ AuthRecord *rr = NULL;
+
+ // get the message data
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend); // flags unused
+ mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
+ char *rdata = get_rdata(&request->msgptr, request->msgend, rdlen);
+ mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend);
+ (void)flags; // Unused
+
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceUpdateRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ if (request->terminate == connection_termination)
+ {
+ // update an individually registered record
+ registered_record_entry *reptr;
+ for (reptr = request->u.reg_recs; reptr; reptr = reptr->next)
+ {
+ if (reptr->key == request->hdr.reg_index)
+ {
+ result = update_record(reptr->rr, rdlen, rdata, ttl);
+ goto end;
+ }
+ }
+ result = mStatus_BadReferenceErr;
+ goto end;
+ }
+
+ // update a record from a service record set
+ for (i = request->u.servicereg.instances; i; i = i->next)
+ {
+ if (request->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
+ else
+ {
+ ExtraResourceRecord *e;
+ for (e = i->srs.Extras; e; e = e->next)
+ if (e->ClientID == request->hdr.reg_index) { rr = &e->r; break; }
+ }
+
+ if (!rr) { result = mStatus_BadReferenceErr; goto end; }
+ result = update_record(rr, rdlen, rdata, ttl);
+ if (result && i->default_local) goto end;
+ else result = mStatus_NoError; // suppress non-local default errors
+ }
+
+end:
+ LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", request->sd,
+ (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
+ rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
+
+ return(result);
+ }
+
+// remove a resource record registered via DNSServiceRegisterRecord()
+mDNSlocal mStatus remove_record(request_state *request)
+ {
+ mStatus err = mStatus_UnknownErr;
+ registered_record_entry *e, **ptr = &request->u.reg_recs;
+
+ while (*ptr && (*ptr)->key != request->hdr.reg_index) ptr = &(*ptr)->next;
+ if (!*ptr) { LogMsg("%3d: DNSServiceRemoveRecord(%u) not found", request->sd, request->hdr.reg_index); return mStatus_BadReferenceErr; }
+ e = *ptr;
+ *ptr = e->next; // unlink
+
+ LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &e->rr->resrec));
+ e->rr->RecordContext = NULL;
+ err = mDNS_Deregister(&mDNSStorage, e->rr);
+ if (err)
+ {
+ LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
+ freeL("registered_record_entry AuthRecord remove_record", e->rr);
+ }
+ freeL("registered_record_entry remove_record", e);
+ return err;
+ }
+
+mDNSlocal mStatus remove_extra(const request_state *const request, service_instance *const serv, mDNSu16 *const rrtype)
+ {
+ mStatus err = mStatus_BadReferenceErr;
+ ExtraResourceRecord *ptr;
+
+ for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
+ {
+ if (ptr->ClientID == request->hdr.reg_index) // found match
+ {
+ *rrtype = ptr->r.resrec.rrtype;
+ return mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
+ }
+ }
+ return err;
+ }
+
+mDNSlocal mStatus handle_removerecord_request(request_state *request)
+ {
+ mStatus err = mStatus_BadReferenceErr;
+ get_flags(&request->msgptr, request->msgend); // flags unused
+
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceRemoveRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ if (request->terminate == connection_termination)
+ err = remove_record(request); // remove individually registered record
+ else
+ {
+ service_instance *i;
+ mDNSu16 rrtype = 0;
+ LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s)", request->sd,
+ (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
+ rrtype ? DNSTypeName(rrtype) : "<NONE>");
+ for (i = request->u.servicereg.instances; i; i = i->next)
+ {
+ err = remove_extra(request, i, &rrtype);
+ if (err && i->default_local) break;
+ else err = mStatus_NoError; // suppress non-local default errors
+ }
+ }
+
+ return(err);
+ }
+
+// If there's a comma followed by another character,
+// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
+// Otherwise, it returns a pointer to the final nul at the end of the string
+mDNSlocal char *FindFirstSubType(char *p)
+ {
+ while (*p)
+ {
+ if (p[0] == '\\' && p[1]) p += 2;
+ else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
+ else p++;
+ }
+ return(p);
+ }
+
+// If there's a comma followed by another character,
+// FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
+// If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
+// Otherwise, it returns a pointer to the final nul at the end of the string
+mDNSlocal char *FindNextSubType(char *p)
+ {
+ while (*p)
+ {
+ if (p[0] == '\\' && p[1]) // If escape character
+ p += 2; // ignore following character
+ else if (p[0] == ',') // If we found a comma
+ {
+ if (p[1]) *p++ = 0;
+ return(p);
+ }
+ else if (p[0] == '.')
+ return(mDNSNULL);
+ else p++;
+ }
+ return(p);
+ }
+
+// Returns -1 if illegal subtype found
+mDNSexport mDNSs32 ChopSubTypes(char *regtype)
+ {
+ mDNSs32 NumSubTypes = 0;
+ char *stp = FindFirstSubType(regtype);
+ while (stp && *stp) // If we found a comma...
+ {
+ if (*stp == ',') return(-1);
+ NumSubTypes++;
+ stp = FindNextSubType(stp);
+ }
+ if (!stp) return(-1);
+ return(NumSubTypes);
+ }
+
+mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
+ {
+ AuthRecord *st = mDNSNULL;
+ if (NumSubTypes)
+ {
+ mDNSs32 i;
+ st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
+ if (!st) return(mDNSNULL);
+ for (i = 0; i < NumSubTypes; i++)
+ {
+ mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
+ while (*p) p++;
+ p++;
+ if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
+ { freeL("ServiceSubTypes", st); return(mDNSNULL); }
+ }
+ }
+ return(st);
+ }
+
+mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
+ {
+ service_instance **ptr, *instance;
+ int instance_size;
+ mStatus result;
+
+ for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next)
+ {
+ if (SameDomainName(&(*ptr)->domain, domain))
+ { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
+ }
+
+ // Special-case hack: We don't advertise SMB service in AutoTunnel domains, because AutoTunnel services have to support IPv6, and our SMB server does not
+ // <rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
+ if (SameDomainName(&request->u.servicereg.type, (const domainname *) "\x4" "_smb" "\x4" "_tcp"))
+ {
+ DomainAuthInfo *AuthInfo = GetAuthInfoForName(&mDNSStorage, domain);
+ if (AuthInfo && AuthInfo->AutoTunnel) return(kDNSServiceErr_Unsupported);
+ }
+
+ instance_size = sizeof(*instance);
+ if (request->u.servicereg.txtlen > sizeof(RDataBody)) instance_size += (request->u.servicereg.txtlen - sizeof(RDataBody));
+ instance = mallocL("service_instance", instance_size);
+ if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
+
+ instance->next = mDNSNULL;
+ instance->request = request;
+ instance->sd = request->sd;
+ instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
+ instance->renameonmemfree = 0;
+ instance->clientnotified = mDNSfalse;
+ instance->default_local = (request->u.servicereg.default_domain && SameDomainName(domain, &localdomain));
+ AssignDomainName(&instance->domain, domain);
+
+ if (request->u.servicereg.num_subtypes && !instance->subtypes)
+ { unlink_and_free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
+
+ LogOperation("%3d: DNSServiceRegister(%#s.%##s%##s, %u) ADDING",
+ instance->sd, &request->u.servicereg.name, &request->u.servicereg.type, domain->c, mDNSVal16(request->u.servicereg.port));
+
+ result = mDNS_RegisterService(&mDNSStorage, &instance->srs,
+ &request->u.servicereg.name, &request->u.servicereg.type, domain,
+ request->u.servicereg.host.c[0] ? &request->u.servicereg.host : NULL,
+ request->u.servicereg.port,
+ request->u.servicereg.txtdata, request->u.servicereg.txtlen,
+ instance->subtypes, request->u.servicereg.num_subtypes,
+ request->u.servicereg.InterfaceID, regservice_callback, instance);
+
+ if (!result) *ptr = instance; // Append this to the end of our request->u.servicereg.instances list
+ else
+ {
+ LogMsg("register_service_instance %#s.%##s%##s error %d",
+ &request->u.servicereg.name, &request->u.servicereg.type, domain->c, result);
+ unlink_and_free_service_instance(instance);
+ }
+
+ return result;
+ }
+
+mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m);
+
+mDNSlocal void regservice_termination_callback(request_state *request)
+ {
+ if (!request) { LogMsg("regservice_termination_callback context is NULL"); return; }
+ while (request->u.servicereg.instances)
+ {
+ service_instance *p = request->u.servicereg.instances;
+ request->u.servicereg.instances = request->u.servicereg.instances->next;
+ // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
+ LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP",
+ request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
+
+ // Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance
+ // We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing
+ // request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time
+ // We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance
+ // because by then we might have already freed p
+ p->request = NULL;
+ if (mDNS_DeregisterService(&mDNSStorage, &p->srs)) unlink_and_free_service_instance(p);
+ // Don't touch service_instance *p after this -- it's likely to have been freed already
+ }
+ if (request->u.servicereg.txtdata)
+ { freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; }
+ if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
+ }
+
+mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d, const mDNSBool add)
+ {
+ request_state *request;
+
+#if APPLE_OSX_mDNSResponder
+ machserver_automatic_registration_domain_changed(&d->name, add);
+#endif // APPLE_OSX_mDNSResponder
+
+ LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->name.c);
+ for (request = all_requests; request; request = request->next)
+ {
+ if (request->terminate != regservice_termination_callback) continue;
+ if (!request->u.servicereg.default_domain) continue;
+ if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
+ {
+ service_instance **ptr = &request->u.servicereg.instances;
+ while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
+ if (add)
+ {
+ // If we don't already have this domain in our list for this registration, add it now
+ if (!*ptr) register_service_instance(request, &d->name);
+ else debugf("udsserver_default_reg_domain_changed %##s already in list, not re-adding", &d->name);
+ }
+ else
+ {
+ // Normally we should not fail to find the specified instance
+ // One case where this can happen is if a uDNS update fails for some reason,
+ // and regservice_callback then calls unlink_and_free_service_instance and disposes of that instance.
+ if (!*ptr)
+ LogMsg("udsserver_default_reg_domain_changed domain %##s not found for service %#s type %s",
+ &d->name, request->u.servicereg.name.c, request->u.servicereg.type_as_string);
+ else
+ {
+ DNameListElem *p;
+ for (p = AutoRegistrationDomains; p; p=p->next)
+ if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
+ if (SameDomainName(&d->name, &p->name)) break;
+ if (p) debugf("udsserver_default_reg_domain_changed %##s still in list, not removing", &d->name);
+ else
+ {
+ mStatus err;
+ service_instance *si = *ptr;
+ *ptr = si->next;
+ if (si->clientnotified) SendServiceRemovalNotification(&si->srs); // Do this *before* clearing si->request backpointer
+ // Now that we've cut this service_instance from the list, we MUST clear the si->request backpointer.
+ // Otherwise what can happen is this: While our mDNS_DeregisterService is in the
+ // process of completing asynchronously, the client cancels the entire operation, so
+ // regservice_termination_callback then runs through the whole list deregistering each
+ // instance, clearing the backpointers, and then disposing the parent request_state object.
+ // However, because this service_instance isn't in the list any more, regservice_termination_callback
+ // has no way to find it and clear its backpointer, and then when our mDNS_DeregisterService finally
+ // completes later with a mStatus_MemFree message, it calls unlink_and_free_service_instance() with
+ // a service_instance with a stale si->request backpointer pointing to memory that's already been freed.
+ si->request = NULL;
+ err = mDNS_DeregisterService(&mDNSStorage, &si->srs);
+ if (err) { LogMsg("udsserver_default_reg_domain_changed err %d", err); unlink_and_free_service_instance(si); }
+ }
+ }
+ }
+ }
+ }
+ }
+
+mDNSlocal mStatus handle_regservice_request(request_state *request)
+ {
+ char name[256]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
+ char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
+ char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
+ domainname d, srv;
+ mStatus err;
+
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ if (interfaceIndex && !InterfaceID)
+ { LogMsg("ERROR: handle_regservice_request - Couldn't find interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
+
+ if (get_string(&request->msgptr, request->msgend, name, sizeof(name)) < 0 ||
+ get_string(&request->msgptr, request->msgend, type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+ get_string(&request->msgptr, request->msgend, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
+ { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
+
+ request->u.servicereg.InterfaceID = InterfaceID;
+ request->u.servicereg.instances = NULL;
+ request->u.servicereg.txtlen = 0;
+ request->u.servicereg.txtdata = NULL;
+ mDNSPlatformStrCopy(request->u.servicereg.type_as_string, type_as_string);
+
+ if (request->msgptr + 2 > request->msgend) request->msgptr = NULL;
+ else
+ {
+ request->u.servicereg.port.b[0] = *request->msgptr++;
+ request->u.servicereg.port.b[1] = *request->msgptr++;
+ }
+
+ request->u.servicereg.txtlen = get_uint16(&request->msgptr, request->msgend);
+ if (request->u.servicereg.txtlen)
+ {
+ request->u.servicereg.txtdata = mallocL("service_info txtdata", request->u.servicereg.txtlen);
+ if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_regservice_request - malloc");
+ mDNSPlatformMemCopy(request->u.servicereg.txtdata, get_rdata(&request->msgptr, request->msgend, request->u.servicereg.txtlen), request->u.servicereg.txtlen);
+ }
+ else request->u.servicereg.txtdata = NULL;
-int udsserver_exit(void)
- {
- dnssd_close(listenfd);
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceRegister(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
-#if !defined(USE_TCP_LOOPBACK)
- // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
- // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
- // It would be nice if we could find a solution to this problem
- if (unlink(MDNS_UDS_SERVERPATH))
- debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
-#endif
+ // Check for sub-types after the service type
+ request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string); // Note: Modifies regtype string to remove trailing subtypes
+ if (request->u.servicereg.num_subtypes < 0)
+ { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", request->u.servicereg.type_as_string); return(mStatus_BadParamErr); }
- if (PID_FILE[0]) unlink(PID_FILE);
+ // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
+ if (!*request->u.servicereg.type_as_string || !MakeDomainNameFromDNSNameString(&request->u.servicereg.type, request->u.servicereg.type_as_string))
+ { LogMsg("ERROR: handle_regservice_request - type_as_string bad %s", request->u.servicereg.type_as_string); return(mStatus_BadParamErr); }
- return 0;
- }
-
-mDNSs32 udsserver_idle(mDNSs32 nextevent)
- {
- request_state *req = all_requests, *tmp, *prev = NULL;
- reply_state *fptr;
- transfer_state result;
- mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
-
- while(req)
- {
- result = t_uninitialized;
- if (req->u_err)
- result = send_undelivered_error(req);
- if (result != t_error && result != t_morecoming && // don't try to send msg if send_error failed
- (req->ts == t_complete || req->ts == t_morecoming))
- {
- while(req->replies)
- {
- if (req->replies->next) req->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
- result = send_msg(req->replies);
- if (result == t_complete)
- {
- fptr = req->replies;
- req->replies = req->replies->next;
- freeL("udsserver_idle", fptr);
- req->time_blocked = 0; // reset failure counter after successful send
- }
- else if (result == t_terminated || result == t_error)
- {
- abort_request(req);
- break;
- }
- else if (result == t_morecoming) break; // client's queues are full, move to next
- }
- }
- if (result == t_morecoming)
+ if (!name[0])
+ {
+ request->u.servicereg.name = mDNSStorage.nicelabel;
+ request->u.servicereg.autoname = mDNStrue;
+ }
+ else
+ {
+ // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
+ if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
{
- if (!req->time_blocked) req->time_blocked = now;
- debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
- if (now - req->time_blocked >= MAX_TIME_BLOCKED)
- {
- LogMsg("Could not write data to client %d after %ld seconds - aborting connection", req->sd, MAX_TIME_BLOCKED / mDNSPlatformOneSecond);
- LogClientInfo(req);
- abort_request(req);
- result = t_terminated;
- }
- else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second
+ int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
+ name[newlen] = 0;
}
- if (result == t_terminated || result == t_error)
- //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
- {
- tmp = req;
- if (prev) prev->next = req->next;
- if (req == all_requests) all_requests = all_requests->next;
- req = req->next;
- freeL("udsserver_idle", tmp);
- }
- else
- {
- prev = req;
- req = req->next;
- }
- }
- return nextevent;
- }
+ if (!MakeDomainLabelFromLiteralString(&request->u.servicereg.name, name))
+ { LogMsg("ERROR: handle_regservice_request - name bad %s", name); return(mStatus_BadParamErr); }
+ request->u.servicereg.autoname = mDNSfalse;
+ }
-mDNSexport void udsserver_info(mDNS *const m)
- {
- mDNSs32 now = mDNS_TimeNow(m);
- mDNSu32 CacheUsed = 0, CacheActive = 0;
- mDNSu32 slot;
- CacheGroup *cg;
- CacheRecord *rr;
- request_state *req;
+ if (*domain)
+ {
+ request->u.servicereg.default_domain = mDNSfalse;
+ if (!MakeDomainNameFromDNSNameString(&d, domain))
+ { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); return(mStatus_BadParamErr); }
+ }
+ else
+ {
+ request->u.servicereg.default_domain = mDNStrue;
+ MakeDomainNameFromDNSNameString(&d, "local.");
+ }
+
+ if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
+ {
+ LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
+ request->u.servicereg.name.c, request->u.servicereg.type.c, d.c); return(mStatus_BadParamErr);
+ }
- LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+ if (!MakeDomainNameFromDNSNameString(&request->u.servicereg.host, host))
+ { LogMsg("ERROR: handle_regservice_request - host bad %s", host); return(mStatus_BadParamErr); }
+ request->u.servicereg.autorename = (flags & kDNSServiceFlagsNoAutoRename ) == 0;
+ request->u.servicereg.allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
- LogMsgNoIdent("Slt Q TTL U Type if len rdata");
- for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
- for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
- {
- CacheUsed++; // Count one cache entity for the CacheGroup object
- for (rr = cg->members; rr; rr=rr->next)
- {
- mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
- CacheUsed++;
- if (rr->CRActiveQuestion) CacheActive++;
- LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
- slot,
- rr->CRActiveQuestion ? "*" : " ",
- remain,
- (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ",
- DNSTypeName(rr->resrec.rrtype),
- ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname,
- CRDisplayString(m, rr));
- usleep(1000); // Limit rate a little so we don't flood syslog too fast
- }
- }
+ // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
+ // a port number of zero. When two instances of the protected client are allowed to run on one
+ // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
+ if (!mDNSIPPortIsZero(request->u.servicereg.port))
+ {
+ int count = CountExistingRegistrations(&srv, request->u.servicereg.port);
+ if (count)
+ LogMsg("Client application registered %d identical instances of service %##s port %u.",
+ count+1, srv.c, mDNSVal16(request->u.servicereg.port));
+ }
- if (m->rrcache_totalused != CacheUsed)
- LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
- if (m->rrcache_active != CacheActive)
- LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
- LogMsgNoIdent("Cache currently contains %lu records; %lu referenced by active questions", CacheUsed, CacheActive);
+ LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
+ request->sd, name, request->u.servicereg.type_as_string, domain, host, mDNSVal16(request->u.servicereg.port));
+ err = register_service_instance(request, &d);
- for (req = all_requests; req; req=req->next)
- LogClientInfo(req);
+ // Set request->terminate first, before adding additional service instances, because the
+ // uds_validatelists uses the request->terminate function pointer to determine what kind
+ // of request this is, and therefore what kind of list validation is required.
+ if (!err)
+ {
+ request->terminate = regservice_termination_callback;
+ if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
+ }
- now = mDNS_TimeNow(m);
- LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
- }
+ if (!err && !*domain)
+ {
+ DNameListElem *ptr;
+ // note that we don't report errors for non-local, non-explicit domains
+ for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
+ if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
+ register_service_instance(request, &ptr->name);
+ }
-#if __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING
-mDNSexport void uds_validatelists(void)
- {
- request_state *req;
- for (req = all_requests; req; req=req->next)
- if (req->sd < 0 && req->sd != -2)
- LogMemCorruption("UDS request list: %p is garbage (%X)", req, req->sd);
+ return(err);
}
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceBrowse
#endif
-mDNSlocal void rename_service(service_instance *srv)
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
- if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
+ const DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : 0;
+ request_state *req = question->QuestionContext;
+ reply_state *rep;
+ (void)m; // Unused
+
+ if (answer->rrtype != kDNSType_PTR)
+ { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
+
+ if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError) != mStatus_NoError)
{
- srv->rename_on_memfree = 1;
- if (mDNS_DeregisterService(gmDNS, &srv->srs)) // If service deregistered already, we can re-register immediately
- regservice_callback(gmDNS, &srv->srs, mStatus_MemFree);
+ LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
+ req->sd, answer->name->c, answer->rdata->u.name.c);
+ return;
}
+
+ LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %d: %s",
+ req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv",
+ mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID), RRDisplayString(m, answer));
+
+ append_reply(req, rep);
}
-mDNSexport void udsserver_handle_configchange(void)
- {
- request_state *req;
+mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d)
+ {
+ browser_t *b, *p;
+ mStatus err;
- for (req = all_requests; req; req = req->next)
- {
- if (req->service_registration)
- {
- service_instance *ptr;
- for (ptr = req->service_registration->instances; ptr; ptr = ptr->next)
- rename_service(ptr);
- }
+ for (p = info->u.browser.browsers; p; p = p->next)
+ {
+ if (SameDomainName(&p->domain, d))
+ { debugf("add_domain_to_browser %##s already in list", d->c); return mStatus_AlreadyRegistered; }
}
- }
-
-mDNSlocal void connect_callback(void *info)
- {
- dnssd_sock_t sd;
- dnssd_socklen_t len;
- unsigned long optval;
- dnssd_sockaddr_t cliaddr;
- request_state *rstate;
- (void)info; // Unused
-
- len = (dnssd_socklen_t) sizeof(cliaddr);
-
- sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
-
- if (sd == dnssd_InvalidSocket)
- {
- if (dnssd_errno() == dnssd_EWOULDBLOCK) return;
- my_perror("ERROR: accept");
- return;
- }
- optval = 1;
-
-#ifdef SO_NOSIGPIPE
- // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
- if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
- {
- my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
- dnssd_close(sd);
- return;
- }
-#endif
-#if defined(_WIN32)
- if (ioctlsocket(sd, FIONBIO, &optval) != 0)
-#else
- if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
-#endif
- {
- my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
- dnssd_close(sd);
- return;
+ b = mallocL("browser_t", sizeof(*b));
+ if (!b) return mStatus_NoMemoryErr;
+ AssignDomainName(&b->domain, d);
+ err = mDNS_StartBrowse(&mDNSStorage, &b->q,
+ &info->u.browser.regtype, d, info->u.browser.interface_id, info->u.browser.ForceMCast, FoundInstance, info);
+ if (err)
+ {
+ LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->u.browser.regtype.c, d->c);
+ freeL("browser_t/add_domain_to_browser", b);
}
-
- // allocate a request_state struct that will live with the socket
- rstate = mallocL("connect_callback", sizeof(request_state));
- if (!rstate) FatalError("ERROR: malloc");
- bzero(rstate, sizeof(request_state));
- rstate->ts = t_morecoming;
- rstate->sd = sd;
-
- LogOperation("%3d: Adding FD", rstate->sd);
- if ( mStatus_NoError != udsSupportAddFDToEventLoop( sd, request_callback, rstate))
- return;
- rstate->next = all_requests;
- all_requests = rstate;
- }
-
-// handler
-mDNSlocal void request_callback(void *info)
- {
- request_state *rstate = info;
- transfer_state result;
- dnssd_sockaddr_t cliaddr;
- int dedicated_error_socket;
-#if defined(_WIN32)
- u_long opt = 1;
-#endif
-
- result = read_msg(rstate);
- if (result == t_morecoming)
+ else
{
- return;
+ b->next = info->u.browser.browsers;
+ info->u.browser.browsers = b;
}
- if (result == t_terminated)
+ return err;
+ }
+
+mDNSlocal void browse_termination_callback(request_state *info)
+ {
+ while (info->u.browser.browsers)
{
- abort_request(rstate);
- unlink_request(rstate);
- return;
+ browser_t *ptr = info->u.browser.browsers;
+ info->u.browser.browsers = ptr->next;
+ LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->sd, ptr->q.qname.c);
+ mDNS_StopBrowse(&mDNSStorage, &ptr->q); // no need to error-check result
+ freeL("browser_t/browse_termination_callback", ptr);
}
- if (result == t_error)
+ }
+
+mDNSlocal void udsserver_automatic_browse_domain_changed(const DNameListElem *const d, const mDNSBool add)
+ {
+ request_state *request;
+ debugf("udsserver_automatic_browse_domain_changed: %s default browse domain %##s", add ? "Adding" : "Removing", d->name.c);
+
+#if APPLE_OSX_mDNSResponder
+ machserver_automatic_browse_domain_changed(&d->name, add);
+#endif // APPLE_OSX_mDNSResponder
+
+ for (request = all_requests; request; request = request->next)
{
- abort_request(rstate);
- unlink_request(rstate);
- return;
+ if (request->terminate != browse_termination_callback) continue; // Not a browse operation
+ if (!request->u.browser.default_domain) continue; // Not an auto-browse operation
+ if (!d->uid || SystemUID(request->uid) || request->uid == d->uid)
+ {
+ browser_t **ptr = &request->u.browser.browsers;
+ while (*ptr && !SameDomainName(&(*ptr)->domain, &d->name)) ptr = &(*ptr)->next;
+ if (add)
+ {
+ // If we don't already have this domain in our list for this browse operation, add it now
+ if (!*ptr) add_domain_to_browser(request, &d->name);
+ else debugf("udsserver_automatic_browse_domain_changed %##s already in list, not re-adding", &d->name);
+ }
+ else
+ {
+ if (!*ptr) LogMsg("udsserver_automatic_browse_domain_changed ERROR %##s not found", &d->name);
+ else
+ {
+ DNameListElem *p;
+ for (p = AutoBrowseDomains; p; p=p->next)
+ if (!p->uid || SystemUID(request->uid) || request->uid == p->uid)
+ if (SameDomainName(&d->name, &p->name)) break;
+ if (p) debugf("udsserver_automatic_browse_domain_changed %##s still in list, not removing", &d->name);
+ else
+ {
+ browser_t *remove = *ptr;
+ *ptr = (*ptr)->next;
+ mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q);
+ freeL("browser_t/udsserver_automatic_browse_domain_changed", remove);
+ }
+ }
+ }
+ }
}
+ }
+
+mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+ {
+ (void)m; // unused
+ if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
+ }
- if (rstate->hdr.version != VERSION)
+mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
+ {
+ // allocate/register legacy and non-legacy _browse PTR record
+ mStatus err;
+ ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr));
+
+ LogOperation("Incrementing %s refcount for %##s",
+ (type == mDNS_DomainTypeBrowse ) ? "browse domain " :
+ (type == mDNS_DomainTypeRegistration ) ? "registration dom" :
+ (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
+
+ mDNS_SetupResourceRecord(&ptr->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, ptr);
+ MakeDomainNameFromDNSNameString(&ptr->ar.namestorage, mDNS_DomainTypeNames[type]);
+ AppendDNSNameString (&ptr->ar.namestorage, "local");
+ AssignDomainName(&ptr->ar.resrec.rdata->u.name, d);
+ err = mDNS_Register(m, &ptr->ar);
+ if (err)
{
- LogMsg("ERROR: client incompatible with daemon (client version = %d, "
- "daemon version = %d)\n", rstate->hdr.version, VERSION);
- abort_request(rstate);
- unlink_request(rstate);
- return;
+ LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
+ mDNSPlatformMemFree(ptr);
}
-
- if (validate_message(rstate) < 0)
+ else
{
- // note that we cannot deliver an error message if validation fails, since the path to the error socket
- // may be contained in the (invalid) message body for some message types
- abort_request(rstate);
- unlink_request(rstate);
- LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
- return;
+ ptr->next = LocalDomainEnumRecords;
+ LocalDomainEnumRecords = ptr;
}
-
- // check if client wants silent operation
- if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
+ }
- dedicated_error_socket = (rstate->hdr.op == reg_record_request || rstate->hdr.op == add_record_request ||
- rstate->hdr.op == update_record_request || rstate->hdr.op == remove_record_request);
-
- if (((rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET) == 0) != dedicated_error_socket)
- LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate->hdr.op, rstate->hdr.flags);
+mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
+ {
+ ARListElem **ptr = &LocalDomainEnumRecords;
+ domainname lhs; // left-hand side of PTR, for comparison
- // check if primary socket is to be used for synchronous errors, else open new socket
- if (dedicated_error_socket)
+ LogOperation("Decrementing %s refcount for %##s",
+ (type == mDNS_DomainTypeBrowse ) ? "browse domain " :
+ (type == mDNS_DomainTypeRegistration ) ? "registration dom" :
+ (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c);
+
+ MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
+ AppendDNSNameString (&lhs, "local");
+
+ while (*ptr)
{
- mStatus err = 0;
- int nwritten;
- dnssd_sock_t errfd = socket(AF_DNSSD, SOCK_STREAM, 0);
- if (errfd == dnssd_InvalidSocket)
+ if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
{
- my_perror("ERROR: socket");
- abort_request(rstate);
- unlink_request(rstate);
+ ARListElem *remove = *ptr;
+ *ptr = (*ptr)->next;
+ mDNS_Deregister(m, &remove->ar);
return;
}
+ else ptr = &(*ptr)->next;
+ }
+ }
- //LogOperation("request_callback: Opened dedicated errfd %d", errfd);
+mDNSlocal void AddAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
+ {
+ DNameListElem *new = mDNSPlatformMemAllocate(sizeof(DNameListElem));
+ if (!new) { LogMsg("ERROR: malloc"); return; }
+ AssignDomainName(&new->name, name);
+ new->uid = uid;
+ new->next = AutoBrowseDomains;
+ AutoBrowseDomains = new;
+ udsserver_automatic_browse_domain_changed(new, mDNStrue);
+ }
- #if defined(USE_TCP_LOOPBACK)
+mDNSlocal void RmvAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
+ {
+ DNameListElem **p = &AutoBrowseDomains;
+ while (*p && (!SameDomainName(&(*p)->name, name) || (*p)->uid != uid)) p = &(*p)->next;
+ if (!*p) LogMsg("RmvAutoBrowseDomain: Got remove event for domain %##s not in list", name->c);
+ else
+ {
+ DNameListElem *ptr = *p;
+ *p = ptr->next;
+ udsserver_automatic_browse_domain_changed(ptr, mDNSfalse);
+ mDNSPlatformMemFree(ptr);
+ }
+ }
+
+mDNSlocal void SetPrefsBrowseDomains(mDNS *m, DNameListElem *browseDomains, mDNSBool add)
+ {
+ DNameListElem *d;
+ for (d = browseDomains; d; d = d->next)
+ {
+ if (add)
{
- mDNSOpaque16 port;
- port.b[0] = rstate->msgdata[0];
- port.b[1] = rstate->msgdata[1];
- rstate->msgdata += 2;
- cliaddr.sin_family = AF_INET;
- cliaddr.sin_port = port.NotAnInteger;
- cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+ RegisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
+ AddAutoBrowseDomain(d->uid, &d->name);
}
- #else
+ else
{
- char ctrl_path[MAX_CTLPATH];
- get_string(&rstate->msgdata, ctrl_path, 256); // path is first element in message buffer
- bzero(&cliaddr, sizeof(cliaddr));
- cliaddr.sun_family = AF_LOCAL;
- strcpy(cliaddr.sun_path, ctrl_path);
+ DeregisterLocalOnlyDomainEnumPTR(m, &d->name, mDNS_DomainTypeBrowse);
+ RmvAutoBrowseDomain(d->uid, &d->name);
}
- #endif
- //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
- if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
+ }
+ }
+
+mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m)
+ {
+ int num_autoname = 0;
+ request_state *req;
+ for (req = all_requests; req; req = req->next)
+ if (req->terminate == regservice_termination_callback && req->u.servicereg.autoname)
+ num_autoname++;
+
+ // If DeviceInfo record is currently registered, see if we need to deregister it
+ if (m->DeviceInfo.resrec.RecordType != kDNSRecordTypeUnregistered)
+ if (num_autoname == 0 || !SameDomainLabelCS(m->DeviceInfo.resrec.name->c, m->nicelabel.c))
{
- //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
- my_perror("ERROR: connect");
- abort_request(rstate);
- unlink_request(rstate);
- return;
+ LogOperation("UpdateDeviceInfoRecord Deregister %##s", m->DeviceInfo.resrec.name);
+ mDNS_Deregister(m, &m->DeviceInfo);
}
-#if defined(_WIN32)
- if (ioctlsocket(errfd, FIONBIO, &opt) != 0)
-#else
- if (fcntl(errfd, F_SETFL, O_NONBLOCK) != 0)
-#endif
+
+ // If DeviceInfo record is not currently registered, see if we need to register it
+ if (m->DeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
+ if (num_autoname > 0)
{
- my_perror("ERROR: could not set control socket to non-blocking mode");
- abort_request(rstate);
- unlink_request(rstate);
- return;
+ mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
+ mDNS_SetupResourceRecord(&m->DeviceInfo, mDNSNULL, mDNSNULL, kDNSType_TXT, kStandardTTL, kDNSRecordTypeAdvisory, mDNSNULL, mDNSNULL);
+ ConstructServiceName(&m->DeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &localdomain);
+ mDNSPlatformMemCopy(m->DeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
+ mDNSPlatformMemCopy(m->DeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
+ m->DeviceInfo.resrec.rdata->u.data[0] = 6 + len; // "model=" plus the device string
+ m->DeviceInfo.resrec.rdlength = 7 + len; // One extra for the length byte at the start of the string
+ LogOperation("UpdateDeviceInfoRecord Register %##s", m->DeviceInfo.resrec.name);
+ mDNS_Register(m, &m->DeviceInfo);
+ }
+ }
+
+mDNSexport void udsserver_handle_configchange(mDNS *const m)
+ {
+ request_state *req;
+ service_instance *ptr;
+ DNameListElem *RegDomains;
+ DNameListElem *BrowseDomains;
+ DNameListElem *p;
+
+ UpdateDeviceInfoRecord(m);
+
+ // For autoname services, see if the default service name has changed, necessitating an automatic update
+ for (req = all_requests; req; req = req->next)
+ if (req->terminate == regservice_termination_callback)
+ if (req->u.servicereg.autoname && !SameDomainLabelCS(req->u.servicereg.name.c, m->nicelabel.c))
+ {
+ req->u.servicereg.name = m->nicelabel;
+ for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
+ {
+ ptr->renameonmemfree = 1;
+ if (ptr->clientnotified) SendServiceRemovalNotification(&ptr->srs);
+ if (mDNS_DeregisterService(m, &ptr->srs)) // If service was deregistered already
+ regservice_callback(m, &ptr->srs, mStatus_MemFree); // we can re-register immediately
+ }
+ }
+
+ // Let the platform layer get the current DNS information
+ mDNS_Lock(m);
+ mDNSPlatformSetDNSConfig(m, mDNSfalse, mDNSfalse, mDNSNULL, &RegDomains, &BrowseDomains);
+ mDNS_Unlock(m);
+
+ // Any automatic registration domains are also implicitly automatic browsing domains
+ if (RegDomains) SetPrefsBrowseDomains(m, RegDomains, mDNStrue); // Add the new list first
+ if (AutoRegistrationDomains) SetPrefsBrowseDomains(m, AutoRegistrationDomains, mDNSfalse); // Then clear the old list
+
+ // Add any new domains not already in our AutoRegistrationDomains list
+ for (p=RegDomains; p; p=p->next)
+ {
+ DNameListElem **pp = &AutoRegistrationDomains;
+ while (*pp && ((*pp)->uid != p->uid || !SameDomainName(&(*pp)->name, &p->name))) pp = &(*pp)->next;
+ if (!*pp) // If not found in our existing list, this is a new default registration domain
+ {
+ RegisterLocalOnlyDomainEnumPTR(m, &p->name, mDNS_DomainTypeRegistration);
+ udsserver_default_reg_domain_changed(p, mDNStrue);
+ }
+ else // else found same domainname in both old and new lists, so no change, just delete old copy
+ {
+ DNameListElem *del = *pp;
+ *pp = (*pp)->next;
+ mDNSPlatformMemFree(del);
}
+ }
+
+ // Delete any domains in our old AutoRegistrationDomains list that are now gone
+ while (AutoRegistrationDomains)
+ {
+ DNameListElem *del = AutoRegistrationDomains;
+ AutoRegistrationDomains = AutoRegistrationDomains->next; // Cut record from list FIRST,
+ DeregisterLocalOnlyDomainEnumPTR(m, &del->name, mDNS_DomainTypeRegistration);
+ udsserver_default_reg_domain_changed(del, mDNSfalse); // before calling udsserver_default_reg_domain_changed()
+ mDNSPlatformMemFree(del);
+ }
+
+ // Now we have our new updated automatic registration domain list
+ AutoRegistrationDomains = RegDomains;
- switch(rstate->hdr.op)
+ // Add new browse domains to internal list
+ if (BrowseDomains) SetPrefsBrowseDomains(m, BrowseDomains, mDNStrue);
+
+ // Remove old browse domains from internal list
+ if (SCPrefBrowseDomains)
+ {
+ SetPrefsBrowseDomains(m, SCPrefBrowseDomains, mDNSfalse);
+ while (SCPrefBrowseDomains)
{
- case reg_record_request: err = handle_regrecord_request (rstate); break;
- case add_record_request: err = handle_add_request (rstate); break;
- case update_record_request: err = handle_update_request (rstate); break;
- case remove_record_request: err = handle_removerecord_request(rstate); break;
- default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
+ DNameListElem *fptr = SCPrefBrowseDomains;
+ SCPrefBrowseDomains = SCPrefBrowseDomains->next;
+ mDNSPlatformMemFree(fptr);
}
+ }
+
+ // Replace the old browse domains array with the new array
+ SCPrefBrowseDomains = BrowseDomains;
+ }
+
+mDNSlocal void AutomaticBrowseDomainChange(mDNS *const m, DNSQuestion *q, const ResourceRecord *const answer, QC_result AddRecord)
+ {
+ (void)m; // unused;
+ (void)q; // unused
+
+ LogOperation("AutomaticBrowseDomainChange: %s automatic browse domain %##s",
+ AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
+
+ if (AddRecord) AddAutoBrowseDomain(0, &answer->rdata->u.name);
+ else RmvAutoBrowseDomain(0, &answer->rdata->u.name);
+ }
+
+mDNSlocal mStatus handle_browse_request(request_state *request)
+ {
+ char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
+ domainname typedn, d, temp;
+ mDNSs32 NumSubTypes;
+ mStatus err = mStatus_NoError;
+
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
+
+ if (get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0) return(mStatus_BadParamErr);
+
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ if (!domain || (domain[0] == '\0')) uDNS_RegisterSearchDomains(&mDNSStorage);
+
+ typedn.c[0] = 0;
+ NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
+ if (NumSubTypes < 0 || NumSubTypes > 1) return(mStatus_BadParamErr);
+ if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1)) return(mStatus_BadParamErr);
+
+ if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) return(mStatus_BadParamErr);
+
+ if (!MakeDomainNameFromDNSNameString(&temp, regtype)) return(mStatus_BadParamErr);
+ // For over-long service types, we only allow domain "local"
+ if (temp.c[0] > 15 && domain[0] == 0) mDNSPlatformStrCopy(domain, "local.");
+
+ // Set up browser info
+ request->u.browser.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
+ request->u.browser.interface_id = InterfaceID;
+ AssignDomainName(&request->u.browser.regtype, &typedn);
+ request->u.browser.default_domain = !domain[0];
+ request->u.browser.browsers = NULL;
+
+ LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, request->u.browser.regtype.c, domain);
+ if (domain[0])
+ {
+ if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
+ err = add_domain_to_browser(request, &d);
+ }
+
+ else
+ {
+ DNameListElem *sdom;
+ for (sdom = AutoBrowseDomains; sdom; sdom = sdom->next)
+ if (!sdom->uid || SystemUID(request->uid) || request->uid == sdom->uid)
+ {
+ err = add_domain_to_browser(request, &sdom->name);
+ if (err)
+ {
+ if (SameDomainName(&sdom->name, &localdomain)) break;
+ else err = mStatus_NoError; // suppress errors for non-local "default" domains
+ }
+ }
+ }
+
+ if (!err) request->terminate = browse_termination_callback;
+
+ return(err);
+ }
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceResolve
+#endif
+
+mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+ {
+ size_t len = 0;
+ char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
+ char *data;
+ reply_state *rep;
+ request_state *req = question->QuestionContext;
+ (void)m; // Unused
+
+ LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
+ req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
+
+ // This code used to do this trick of just keeping a copy of the pointer to
+ // the answer record in the cache, but the unicast query code doesn't currently
+ // put its answer records in the cache, so for now we can't do this.
- //LogOperation("request_callback: Returning error code %d on socket %d", err, errfd);
- err = dnssd_htonl(err);
- nwritten = send(errfd, (dnssd_sockbuf_t) &err, sizeof(err), 0);
- // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
- // If not, we don't attempt to handle this failure, but we do log it.
- if (nwritten < (int)sizeof(err))
- LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
- nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
- //else LogOperation("request_callback: Returned error code %d on socket %d", err, errfd);
- dnssd_close(errfd);
- //LogOperation("request_callback: Closed errfd %d", errfd);
- reset_connected_rstate(rstate); // Reset ready to accept the next request on this pipe
+ if (!AddRecord)
+ {
+ if (answer->rrtype == kDNSType_SRV && req->u.resolve.srv == answer) req->u.resolve.srv = mDNSNULL;
+ if (answer->rrtype == kDNSType_TXT && req->u.resolve.txt == answer) req->u.resolve.txt = mDNSNULL;
+ return;
}
- else
+
+ if (answer->rrtype == kDNSType_SRV) req->u.resolve.srv = answer;
+ if (answer->rrtype == kDNSType_TXT) req->u.resolve.txt = answer;
+
+ if (!req->u.resolve.txt || !req->u.resolve.srv) return; // only deliver result to client if we have both answers
+
+ ConvertDomainNameToCString(answer->name, fullname);
+ ConvertDomainNameToCString(&req->u.resolve.srv->rdata->u.srv.target, target);
+
+ // calculate reply length
+ len += sizeof(DNSServiceFlags);
+ len += sizeof(mDNSu32); // interface index
+ len += sizeof(DNSServiceErrorType);
+ len += strlen(fullname) + 1;
+ len += strlen(target) + 1;
+ len += 2 * sizeof(mDNSu16); // port, txtLen
+ len += req->u.resolve.txt->rdlength;
+
+ // allocate/init reply header
+ rep = create_reply(resolve_reply_op, len, req);
+ rep->rhdr->flags = dnssd_htonl(0);
+ rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID));
+ rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
+
+ data = rep->sdata;
+
+ // write reply data to message
+ put_string(fullname, &data);
+ put_string(target, &data);
+ *data++ = req->u.resolve.srv->rdata->u.srv.port.b[0];
+ *data++ = req->u.resolve.srv->rdata->u.srv.port.b[1];
+ put_uint16(req->u.resolve.txt->rdlength, &data);
+ put_rdata(req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
+
+ append_reply(req, rep);
+ }
+
+mDNSlocal void resolve_termination_callback(request_state *request)
+ {
+ LogOperation("%3d: DNSServiceResolve(%##s) STOP", request->sd, request->u.resolve.qtxt.qname.c);
+ mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
+ mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
+ }
+
+mDNSlocal mStatus handle_resolve_request(request_state *request)
+ {
+ char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
+ domainname fqdn;
+ mStatus err;
+
+ // extract the data from the message
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ if (interfaceIndex && !InterfaceID)
+ { LogMsg("ERROR: handle_resolve_request bad interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
+
+ if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
+ get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+ { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
+
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceResolve(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
+ { LogMsg("ERROR: handle_resolve_request bad “%s” “%s” “%s”", name, regtype, domain); return(mStatus_BadParamErr); }
+
+ mDNSPlatformMemZero(&request->u.resolve, sizeof(request->u.resolve));
+
+ // format questions
+ request->u.resolve.qsrv.InterfaceID = InterfaceID;
+ request->u.resolve.qsrv.Target = zeroAddr;
+ AssignDomainName(&request->u.resolve.qsrv.qname, &fqdn);
+ request->u.resolve.qsrv.qtype = kDNSType_SRV;
+ request->u.resolve.qsrv.qclass = kDNSClass_IN;
+ request->u.resolve.qsrv.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
+ request->u.resolve.qsrv.ExpectUnique = mDNStrue;
+ request->u.resolve.qsrv.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
+ request->u.resolve.qsrv.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ request->u.resolve.qsrv.QuestionCallback = resolve_result_callback;
+ request->u.resolve.qsrv.QuestionContext = request;
+
+ request->u.resolve.qtxt.InterfaceID = InterfaceID;
+ request->u.resolve.qtxt.Target = zeroAddr;
+ AssignDomainName(&request->u.resolve.qtxt.qname, &fqdn);
+ request->u.resolve.qtxt.qtype = kDNSType_TXT;
+ request->u.resolve.qtxt.qclass = kDNSClass_IN;
+ request->u.resolve.qtxt.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
+ request->u.resolve.qtxt.ExpectUnique = mDNStrue;
+ request->u.resolve.qtxt.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
+ request->u.resolve.qtxt.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
+ request->u.resolve.qtxt.QuestionContext = request;
+
+ // ask the questions
+ LogOperation("%3d: DNSServiceResolve(%##s) START", request->sd, request->u.resolve.qsrv.qname.c);
+ err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
+ if (!err)
{
- switch(rstate->hdr.op)
- {
- case resolve_request: handle_resolve_request (rstate); break;
- case query_request: handle_query_request (rstate); break;
- case browse_request: handle_browse_request (rstate); break;
- case reg_service_request: handle_regservice_request(rstate); break;
- case enumeration_request: handle_enum_request (rstate); break;
- case reconfirm_record_request: handle_reconfirm_request (rstate); break;
- case setdomain_request: handle_setdomain_request (rstate); break;
- default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
- }
+ err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
+ if (err) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
}
+
+ if (!err) request->terminate = resolve_termination_callback;
+
+ return(err);
}
-// mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceQueryRecord
+#endif
+
+// mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
// the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
// to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
// the mDNSCore operation if the client dies or closes its socket.
// massage the name parameters appropriately, but the rest of the operations (making the query call,
// delivering the result to the client, and termination) are identical.
-mDNSlocal void handle_query_request(request_state *rstate)
- {
- DNSServiceFlags flags;
- uint32_t ifi;
- char name[256];
- uint16_t rrtype, rrclass;
- char *ptr;
- mStatus result;
- mDNSInterfaceID InterfaceID;
- DNSQuestion *q;
-
- if (rstate->ts != t_complete)
- {
- LogMsg("ERROR: handle_query_request - transfer state != t_complete");
- goto error;
- }
- ptr = rstate->msgdata;
- if (!ptr)
- {
- LogMsg("ERROR: handle_query_request - NULL msgdata");
- goto error;
- }
-
- flags = get_flags(&ptr);
- ifi = get_long(&ptr);
- if (get_string(&ptr, name, 256) < 0) goto bad_param;
- rrtype = get_short(&ptr);
- rrclass = get_short(&ptr);
- InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
- if (ifi && !InterfaceID) goto bad_param;
-
- q = mallocL("DNSQuestion", sizeof(DNSQuestion));
- if (!q) FatalError("ERROR: handle_query - malloc");
- bzero(q, sizeof(DNSQuestion));
-
- q->InterfaceID = InterfaceID;
- q->Target = zeroAddr;
- if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }
- q->qtype = rrtype;
- q->qclass = rrclass;
- q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
- q->ExpectUnique = mDNSfalse;
- q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
- q->QuestionCallback = question_result_callback;
- q->QuestionContext = rstate;
-
- rstate->termination_context = q;
- rstate->terminate = question_termination_callback;
-
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) START", rstate->sd, q->qname.c, DNSTypeName(q->qtype));
- result = mDNS_StartQuery(gmDNS, q);
- if (result != mStatus_NoError) LogMsg("ERROR: mDNS_StartQuery: %d", (int)result);
-
- if (result) rstate->terminate = NULL;
- if (deliver_error(rstate, result) < 0) goto error;
- return;
-
-bad_param:
- deliver_error(rstate, mStatus_BadParamErr);
- rstate->terminate = NULL; // don't try to terminate insuccessful Core calls
-error:
- abort_request(rstate);
- unlink_request(rstate);
- return;
- }
-
-mDNSlocal void handle_resolve_request(request_state *rstate)
- {
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- mDNSInterfaceID InterfaceID;
- char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
- char *ptr; // message data pointer
- domainname fqdn;
- resolve_termination_t *term;
- mStatus err;
-
- if (rstate->ts != t_complete)
- {
- LogMsg("ERROR: handle_resolve_request - transfer state != t_complete");
- abort_request(rstate);
- unlink_request(rstate);
- return;
- }
-
- // extract the data from the message
- ptr = rstate->msgdata;
- if (!ptr)
- {
- LogMsg("ERROR: handle_resolve_request - NULL msgdata");
- abort_request(rstate);
- unlink_request(rstate);
- return;
- }
- flags = get_flags(&ptr);
- interfaceIndex = get_long(&ptr);
- InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
- if (interfaceIndex && !InterfaceID)
- { LogMsg("ERROR: handle_resolve_request - Couldn't find InterfaceID for interfaceIndex %d", interfaceIndex); goto bad_param; }
- if (get_string(&ptr, name, 256) < 0 ||
- get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
- { LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); goto bad_param; }
-
- // free memory in rstate since we don't need it anymore
- freeL("handle_resolve_request", rstate->msgbuf);
- rstate->msgbuf = NULL;
-
- if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
- { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
-
- // set up termination info
- term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
- bzero(term, sizeof(*term));
- if (!term) FatalError("ERROR: malloc");
-
- // format questions
- term->qsrv.InterfaceID = InterfaceID;
- term->qsrv.Target = zeroAddr;
- memcpy(&term->qsrv.qname, &fqdn, MAX_DOMAIN_NAME);
- term->qsrv.qtype = kDNSType_SRV;
- term->qsrv.qclass = kDNSClass_IN;
- term->qsrv.LongLived = mDNSfalse;
- term->qsrv.ExpectUnique = mDNStrue;
- term->qsrv.ForceMCast = mDNSfalse;
- term->qsrv.QuestionCallback = resolve_result_callback;
- term->qsrv.QuestionContext = rstate;
-
- term->qtxt.InterfaceID = InterfaceID;
- term->qtxt.Target = zeroAddr;
- memcpy(&term->qtxt.qname, &fqdn, MAX_DOMAIN_NAME);
- term->qtxt.qtype = kDNSType_TXT;
- term->qtxt.qclass = kDNSClass_IN;
- term->qtxt.LongLived = mDNSfalse;
- term->qtxt.ExpectUnique = mDNStrue;
- term->qtxt.ForceMCast = mDNSfalse;
- term->qtxt.QuestionCallback = resolve_result_callback;
- term->qtxt.QuestionContext = rstate;
-
- term->rstate = rstate;
- rstate->termination_context = term;
- rstate->terminate = resolve_termination_callback;
-
- // ask the questions
- LogOperation("%3d: DNSServiceResolve(%##s) START", rstate->sd, term->qsrv.qname.c);
- err = mDNS_StartQuery(gmDNS, &term->qsrv);
- if (!err) err = mDNS_StartQuery(gmDNS, &term->qtxt);
-
- if (err)
- {
- freeL("handle_resolve_request", term);
- rstate->terminate = NULL; // prevent abort_request() from invoking termination callback
- }
- if (deliver_error(rstate, err) < 0 || err)
- {
- abort_request(rstate);
- unlink_request(rstate);
- }
- return;
-
-bad_param:
- deliver_error(rstate, mStatus_BadParamErr);
- abort_request(rstate);
- unlink_request(rstate);
- }
-
-mDNSlocal void resolve_termination_callback(void *context)
- {
- resolve_termination_t *term = context;
- request_state *rs;
-
- if (!term)
- {
- LogMsg("ERROR: resolve_termination_callback: double termination");
- return;
- }
- rs = term->rstate;
- LogOperation("%3d: DNSServiceResolve(%##s) STOP", rs->sd, term->qtxt.qname.c);
-
- mDNS_StopQuery(gmDNS, &term->qtxt);
- mDNS_StopQuery(gmDNS, &term->qsrv);
-
- freeL("resolve_termination_callback", term);
- rs->termination_context = NULL;
- }
-
-mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
- {
- size_t len = 0;
- char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
- char *data;
- transfer_state result;
- reply_state *rep;
- request_state *rs = question->QuestionContext;
- resolve_termination_t *res = rs->termination_context;
- (void)m; // Unused
+// what gets called when a resolve is completed and we need to send the data back to the client
+mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+ {
+ char name[MAX_ESCAPED_DOMAIN_NAME];
+ request_state *req = question->QuestionContext;
+ reply_state *rep;
+ char *data;
+ size_t len;
+ DNSServiceErrorType error = kDNSServiceErr_NoError;
+ (void)m; // Unused
- LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
- rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
-
- // This code used to do this trick of just keeping a copy of the pointer to
- // the answer record in the cache, but the unicast query code doesn't currently
- // put its answer records in the cache, so for now we can't do this.
-
- if (!AddRecord)
+ LogOperation("%3d: %s(%##s, %s) %s %s", req->sd,
+ req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
+ question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
+
+ if (answer->RecordType == kDNSRecordTypePacketNegative)
{
- // After unicast query code is updated to store its records in the common cache, use this...
- // if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
- // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
- // intead of this...
- if (answer->rrtype == kDNSType_SRV && res->srv && SameRDataBody(answer, (RDataBody *)&res->srvdata))
- res->srv = mDNSfalse;
- if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
- res->txt = mDNSfalse;
- return;
+ error = kDNSServiceErr_NoSuchRecord;
+ ConvertDomainNameToCString(&question->qname, name);
+ AddRecord = mDNStrue;
}
+ else
+ ConvertDomainNameToCString(answer->name, name);
- // After unicast query code is updated to store its records in the common cache, use this...
- // if (answer->rrtype == kDNSType_SRV) res->srv = answer;
- // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
- // intead of this...
- if (answer->rrtype == kDNSType_SRV)
- {
- // Don't copy structure in its entirety, because the CacheEntity may be an intentionally truncated object
- // (to economize on space) and reading past the end may run into unmapped memory, causing a crash.
- //res->srvdata = answer->rdata->u.srv;
- // The AssignDomainName() macro is smart enough to only copy the valid part of the name, and not
- // try to copy the full 255 bytes which may not all be there.
- AssignDomainName(&res->srvdata.target, &answer->rdata->u.srv.target);
- res->srvdata.port = answer->rdata->u.srv.port;
- res->srv = mDNStrue;
- }
- if (answer->rrtype == kDNSType_TXT)
- {
- if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
- res->txtlen = answer->rdlength;
- mDNSPlatformMemCopy(answer->rdata->u.data, res->txtdata, res->txtlen);
- res->txt = mDNStrue;
- }
-
- if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
-
- ConvertDomainNameToCString(answer->name, fullname);
- ConvertDomainNameToCString(&res->srvdata.target, target);
-
- // calculate reply length
- len += sizeof(DNSServiceFlags);
- len += sizeof(uint32_t); // interface index
- len += sizeof(DNSServiceErrorType);
- len += strlen(fullname) + 1;
- len += strlen(target) + 1;
- len += 2 * sizeof(uint16_t); // port, txtLen
- len += res->txtlen;
-
- // allocate/init reply header
- rep = create_reply(resolve_reply, len, rs);
- rep->rhdr->flags = dnssd_htonl(0);
- rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
- rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
-
- data = rep->sdata;
-
- // write reply data to message
- put_string(fullname, &data);
- put_string(target, &data);
- *data++ = res->srvdata.port.b[0];
- *data++ = res->srvdata.port.b[1];
- put_short(res->txtlen, &data);
- put_rdata(res->txtlen, res->txtdata, &data);
-
- result = send_msg(rep);
- if (result == t_error || result == t_terminated)
- {
- abort_request(rs);
- unlink_request(rs);
- freeL("resolve_result_callback", rep);
- }
- else if (result == t_complete) freeL("resolve_result_callback", rep);
- else append_reply(rs, rep);
- }
+ len = sizeof(DNSServiceFlags); // calculate reply data length
+ len += sizeof(mDNSu32); // interface index
+ len += sizeof(DNSServiceErrorType);
+ len += strlen(name) + 1;
+ len += 3 * sizeof(mDNSu16); // type, class, rdlen
+ len += answer->rdlength;
+ len += sizeof(mDNSu32); // TTL
-// what gets called when a resolve is completed and we need to send the data back to the client
-mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
- {
- char *data;
- char name[MAX_ESCAPED_DOMAIN_NAME];
- request_state *req = question->QuestionContext;
- reply_state *rep;
- size_t len;
- (void)m; // Unused
-
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
- //mDNS_StopQuery(m, question);
-
- // calculate reply data length
- len = sizeof(DNSServiceFlags);
- len += 2 * sizeof(uint32_t); // if index + ttl
- len += sizeof(DNSServiceErrorType);
- len += 3 * sizeof(uint16_t); // type, class, rdlen
- len += answer->rdlength;
- ConvertDomainNameToCString(answer->name, name);
- len += strlen(name) + 1;
-
- rep = create_reply(query_reply, len, req);
-
- rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
- rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
- rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
-
- data = rep->sdata;
-
- put_string(name, &data);
- put_short(answer->rrtype, &data);
- put_short(answer->rrclass, &data);
- put_short(answer->rdlength, &data);
- put_rdata(answer->rdlength, answer->rdata->u.data, &data);
- put_long(AddRecord ? answer->rroriginalttl : 0, &data);
-
- append_reply(req, rep);
- return;
- }
-
-mDNSlocal void question_termination_callback(void *context)
- {
- DNSQuestion *q = context;
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
- mDNS_StopQuery(gmDNS, q); // no need to error check
- freeL("question_termination_callback", q);
- }
+ rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
-// If there's a comma followed by another character,
-// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
-// Otherwise, it returns a pointer to the final nul at the end of the string
-mDNSlocal char *FindFirstSubType(char *p)
- {
- while (*p)
+ rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
+ rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID));
+ rep->rhdr->error = dnssd_htonl(error);
+
+ data = rep->sdata;
+
+ put_string(name, &data);
+
+ if (answer->RecordType == kDNSRecordTypePacketNegative)
{
- if (p[0] == '\\' && p[1]) p += 2;
- else if (p[0] == ',' && p[1]) { *p++ = 0; return(p); }
- else p++;
+ put_uint16(question->qtype, &data);
+ put_uint16(question->qclass, &data);
+ put_uint16(0, &data);
+ put_rdata(0, mDNSNULL, &data);
+ put_uint32(0, &data);
}
- return(p);
+ else
+ {
+ put_uint16(answer->rrtype, &data);
+ put_uint16(answer->rrclass, &data);
+ put_uint16(answer->rdlength, &data);
+ //put_rdata(answer->rdlength, answer->rdata->u.data, &data);
+ if (!putRData(mDNSNULL, (mDNSu8 *)data, (mDNSu8 *)rep->rhdr + len, answer))
+ LogMsg("queryrecord_result_callback putRData failed %d", (mDNSu8 *)rep->rhdr + len - (mDNSu8 *)data);
+ data += answer->rdlength;
+ put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
+ }
+
+ append_reply(req, rep);
}
-// If there's a comma followed by another character,
-// FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
-// If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
-// Otherwise, it returns a pointer to the final nul at the end of the string
-mDNSlocal char *FindNextSubType(char *p)
+mDNSlocal void queryrecord_termination_callback(request_state *request)
{
- while (*p)
- {
- if (p[0] == '\\' && p[1]) // If escape character
- p += 2; // ignore following character
- else if (p[0] == ',') // If we found a comma
- {
- if (p[1]) *p++ = 0;
- return(p);
- }
- else if (p[0] == '.')
- return(mDNSNULL);
- else p++;
- }
- return(p);
+ LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP",
+ request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype));
+ mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q); // no need to error check
}
-// Returns -1 if illegal subtype found
-mDNSexport mDNSs32 ChopSubTypes(char *regtype)
+mDNSlocal mStatus handle_queryrecord_request(request_state *request)
{
- mDNSs32 NumSubTypes = 0;
- char *stp = FindFirstSubType(regtype);
- while (stp && *stp) // If we found a comma...
- {
- if (*stp == ',') return(-1);
- NumSubTypes++;
- stp = FindNextSubType(stp);
- }
- if (!stp) return(-1);
- return(NumSubTypes);
+ char name[256];
+ mDNSu16 rrtype, rrclass;
+ mStatus err;
+
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
+
+ if (get_string(&request->msgptr, request->msgend, name, 256) < 0) return(mStatus_BadParamErr);
+ rrtype = get_uint16(&request->msgptr, request->msgend);
+ rrclass = get_uint16(&request->msgptr, request->msgend);
+
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ mDNSPlatformMemZero(&request->u.queryrecord.q, sizeof(&request->u.queryrecord.q));
+
+ request->u.queryrecord.q.InterfaceID = InterfaceID;
+ request->u.queryrecord.q.Target = zeroAddr;
+ if (!MakeDomainNameFromDNSNameString(&request->u.queryrecord.q.qname, name)) return(mStatus_BadParamErr);
+ request->u.queryrecord.q.qtype = rrtype;
+ request->u.queryrecord.q.qclass = rrclass;
+ request->u.queryrecord.q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
+ request->u.queryrecord.q.ExpectUnique = mDNSfalse;
+ request->u.queryrecord.q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
+ request->u.queryrecord.q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ request->u.queryrecord.q.QuestionCallback = queryrecord_result_callback;
+ request->u.queryrecord.q.QuestionContext = request;
+
+ LogOperation("%3d: DNSServiceQueryRecord(%##s, %s, %X) START",
+ request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), flags);
+ err = mDNS_StartQuery(&mDNSStorage, &request->u.queryrecord.q);
+ if (err) LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
+
+ if (!err) request->terminate = queryrecord_termination_callback;
+
+ return(err);
}
-mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceEnumerateDomains
+#endif
+
+mDNSlocal reply_state *format_enumeration_reply(request_state *request,
+ const char *domain, DNSServiceFlags flags, mDNSu32 ifi, DNSServiceErrorType err)
{
- AuthRecord *st = mDNSNULL;
- if (NumSubTypes)
- {
- mDNSs32 i;
- st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
- if (!st) return(mDNSNULL);
- for (i = 0; i < NumSubTypes; i++)
- {
- mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
- while (*p) p++;
- p++;
- if (!MakeDomainNameFromDNSNameString(st[i].resrec.name, p))
- { freeL("ServiceSubTypes", st); return(mDNSNULL); }
- }
- }
- return(st);
+ size_t len;
+ reply_state *reply;
+ char *data;
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(mDNSu32);
+ len += sizeof(DNSServiceErrorType);
+ len += strlen(domain) + 1;
+
+ reply = create_reply(enumeration_reply_op, len, request);
+ reply->rhdr->flags = dnssd_htonl(flags);
+ reply->rhdr->ifi = dnssd_htonl(ifi);
+ reply->rhdr->error = dnssd_htonl(err);
+ data = reply->sdata;
+ put_string(domain, &data);
+ return reply;
}
-#ifdef _HAVE_SETDOMAIN_SUPPORT_
-mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
+mDNSlocal void enum_termination_callback(request_state *request)
{
- (void)m; // unused
- if (result == mStatus_MemFree) free(rr->RecordContext); // context is the enclosing list structure
+ mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
+ mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_default);
}
-#endif
-mDNSlocal void handle_setdomain_request(request_state *request)
+mDNSlocal void enum_result_callback(mDNS *const m,
+ DNSQuestion *const question, const ResourceRecord *const answer, QC_result AddRecord)
{
- mStatus err = mStatus_NoError;
- char *ptr;
- char domainstr[MAX_ESCAPED_DOMAIN_NAME];
- domainname domain;
- DNSServiceFlags flags;
-#ifdef _HAVE_SETDOMAIN_SUPPORT_
- struct xucred xuc;
- socklen_t xuclen;
-#endif
+ char domain[MAX_ESCAPED_DOMAIN_NAME];
+ request_state *request = question->QuestionContext;
+ DNSServiceFlags flags = 0;
+ reply_state *reply;
+ (void)m; // Unused
+
+ if (answer->rrtype != kDNSType_PTR) return;
- if (request->ts != t_complete)
- {
- LogMsg("ERROR: handle_setdomain_request - transfer state != t_complete");
- abort_request(request);
- unlink_request(request);
- return;
- }
-
- // extract flags/domain from message
- ptr = request->msgdata;
- flags = get_flags(&ptr);
- if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- !MakeDomainNameFromDNSNameString(&domain, domainstr))
- { err = mStatus_BadParamErr; goto end; }
-
- freeL("handle_setdomain_request", request->msgbuf);
- request->msgbuf = NULL;
-
- debugf("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
-
-#ifdef _HAVE_SETDOMAIN_SUPPORT_
- // this functionality currently only used for Apple-specific configuration, so we don't burned other platforms by mandating
- // the existence of this socket option
- xuclen = sizeof(xuc);
- if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
- { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
- if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
- LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
-
- if (flags & kDNSServiceFlagsAdd)
- {
- // register a local-only PRT record
- default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
- if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
- mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, free_defdomain, newelem);
- MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
- AppendDNSNameString (&newelem->ptr_rec.resrec.name, "local");
- AssignDomainName(&newelem->ptr_rec.resrec.rdata->u.name, &domain);
- newelem->uid = xuc.cr_uid;
- err = mDNS_Register(gmDNS, &newelem->ptr_rec);
- if (err) free(newelem);
- else
- {
- // link into list
- newelem->next = default_browse_list;
- default_browse_list = newelem;
- }
-
- }
- else
+ // We only return add/remove events for the browse and registration lists
+ // For the default browse and registration answers, we only give an "ADD" event
+ if (question == &request->u.enumeration.q_default && !AddRecord) return;
+
+ if (AddRecord)
{
- // remove - find in list, deregister
- default_browse_list_t *ptr = default_browse_list, *prev = NULL;
- while (ptr)
- {
- if (SameDomainName(&ptr->ptr_rec.resrec.rdata->u.name, &domain))
- {
- if (prev) prev->next = ptr->next;
- else default_browse_list = ptr->next;
- err = mDNS_Deregister(gmDNS, &ptr->ptr_rec);
- break;
- }
- prev = ptr;
- ptr = ptr->next;
- }
- if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
+ flags |= kDNSServiceFlagsAdd;
+ if (question == &request->u.enumeration.q_default) flags |= kDNSServiceFlagsDefault;
}
-#else
- err = mStatus_NoError;
-#endif // _HAVE_SETDOMAIN_SUPPORT_
-
- end:
- deliver_error(request, err);
- abort_request(request);
- unlink_request(request);
- }
-// Generates a response message giving name, type, domain, plus interface index,
-// suitable for a browse result or service registration result.
-// On successful completion rep is set to point to a malloc'd reply_state struct
-mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
+ ConvertDomainNameToCString(&answer->rdata->u.name, domain);
+ // Note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
+ // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
+ // network, so we just pass kDNSServiceInterfaceIndexAny
+ reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
+ if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; }
+ append_reply(request, reply);
+ }
+
+mDNSlocal mStatus handle_enum_request(request_state *request)
{
- domainlabel name;
- domainname type, dom;
- *rep = NULL;
- if (!DeconstructServiceName(servicename, &name, &type, &dom))
- return kDNSServiceErr_Invalid;
- else
- {
- char namestr[MAX_DOMAIN_LABEL+1];
- char typestr[MAX_ESCAPED_DOMAIN_NAME];
- char domstr [MAX_ESCAPED_DOMAIN_NAME];
- int len;
- char *data;
+ mStatus err;
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ DNSServiceFlags reg = flags & kDNSServiceFlagsRegistrationDomains;
+ mDNS_DomainType t_all = reg ? mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
+ mDNS_DomainType t_default = reg ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
+ mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
+
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceEnumerateDomains(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ // allocate context structures
+ uDNS_RegisterSearchDomains(&mDNSStorage);
+
+ // enumeration requires multiple questions, so we must link all the context pointers so that
+ // necessary context can be reached from the callbacks
+ request->u.enumeration.q_all .QuestionContext = request;
+ request->u.enumeration.q_default.QuestionContext = request;
- ConvertDomainLabelToCString_unescaped(&name, namestr);
- ConvertDomainNameToCString(&type, typestr);
- ConvertDomainNameToCString(&dom, domstr);
-
- // Calculate reply data length
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t); // if index
- len += sizeof(DNSServiceErrorType);
- len += (int) (strlen(namestr) + 1);
- len += (int) (strlen(typestr) + 1);
- len += (int) (strlen(domstr) + 1);
-
- // Build reply header
- *rep = create_reply(query_reply, len, request);
- (*rep)->rhdr->flags = dnssd_htonl(0);
- (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
- (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
-
- // Build reply body
- data = (*rep)->sdata;
- put_string(namestr, &data);
- put_string(typestr, &data);
- put_string(domstr, &data);
+ // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
+ if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
- return mStatus_NoError;
+ // make the calls
+ LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", request->sd, flags,
+ (flags & kDNSServiceFlagsBrowseDomains ) ? "kDNSServiceFlagsBrowseDomains" :
+ (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
+ err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_all, t_all, NULL, InterfaceID, enum_result_callback, request);
+ if (!err)
+ {
+ err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_default, t_default, NULL, InterfaceID, enum_result_callback, request);
+ if (err) mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all);
}
+ if (!err) request->terminate = enum_termination_callback;
+
+ return(err);
}
-mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceReconfirmRecord & Misc
+#endif
+
+mDNSlocal mStatus handle_reconfirm_request(request_state *request)
{
- request_state *req = question->QuestionContext;
- reply_state *rep;
- (void)m; // Unused
+ mStatus status = mStatus_BadParamErr;
+ AuthRecord *rr = read_rr_from_ipc_msg(request, 0, 0);
+ if (rr)
+ {
+ status = mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
+ LogOperation(
+ (status == mStatus_NoError) ?
+ "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
+ "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
+ request->sd, RRDisplayString(&mDNSStorage, &rr->resrec),
+ mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID), status);
+ freeL("AuthRecord/handle_reconfirm_request", rr);
+ }
+ return(status);
+ }
- if (answer->rrtype != kDNSType_PTR)
- { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
+mDNSlocal mStatus handle_setdomain_request(request_state *request)
+ {
+ char domainstr[MAX_ESCAPED_DOMAIN_NAME];
+ domainname domain;
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ (void)flags; // Unused
+ if (get_string(&request->msgptr, request->msgend, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+ !MakeDomainNameFromDNSNameString(&domain, domainstr))
+ { LogMsg("%3d: DNSServiceSetDefaultDomainForUser(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ LogOperation("%3d: DNSServiceSetDefaultDomainForUser(%##s)", request->sd, domain.c);
+ return(mStatus_NoError);
+ }
+
+typedef packedstruct
+ {
+ mStatus err;
+ mDNSu32 len;
+ mDNSu32 vers;
+ } DaemonVersionReply;
- if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError)
+mDNSlocal void handle_getproperty_request(request_state *request)
+ {
+ const mStatus BadParamErr = dnssd_htonl(mStatus_BadParamErr);
+ char prop[256];
+ if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
{
- LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
- req->sd, answer->name->c, answer->rdata->u.name.c);
- return;
+ LogOperation("%3d: DNSServiceGetProperty(%s)", request->sd, prop);
+ if (!strcmp(prop, kDNSServiceProperty_DaemonVersion))
+ {
+ DaemonVersionReply x = { 0, dnssd_htonl(4), dnssd_htonl(_DNS_SD_H) };
+ send_all(request->sd, (const char *)&x, sizeof(x));
+ return;
+ }
}
- LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
- req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
+ // If we didn't recogize the requested property name, return BadParamErr
+ send_all(request->sd, (const char *)&BadParamErr, sizeof(BadParamErr));
+ }
- if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);
- append_reply(req, rep);
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceNATPortMappingCreate
+#endif
+
+#define DNSServiceProtocol(X) ((X) == NATOp_AddrRequest ? 0 : (X) == NATOp_MapUDP ? kDNSServiceProtocol_UDP : kDNSServiceProtocol_TCP)
+
+mDNSlocal void port_mapping_termination_callback(request_state *request)
+ {
+ LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP", request->sd,
+ DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+ mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease);
+ mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
}
-mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
+// Called via function pointer when we get a NAT-PMP address request or port mapping response
+mDNSlocal void port_mapping_create_request_callback(mDNS *m, NATTraversalInfo *n)
{
- browser_t *b, *p;
- mStatus err;
+ request_state *request = (request_state *)n->clientContext;
+ reply_state *rep;
+ int replyLen;
+ char *data;
+
+ if (!request) { LogMsg("port_mapping_create_request_callback called with unknown request_state object"); return; }
+
+ // calculate reply data length
+ replyLen = sizeof(DNSServiceFlags);
+ replyLen += 3 * sizeof(mDNSu32); // if index + addr + ttl
+ replyLen += sizeof(DNSServiceErrorType);
+ replyLen += 2 * sizeof(mDNSu16); // Internal Port + External Port
+ replyLen += sizeof(mDNSu8); // protocol
+
+ rep = create_reply(port_mapping_reply_op, replyLen, request);
+
+ rep->rhdr->flags = dnssd_htonl(0);
+ rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, n->InterfaceID));
+ rep->rhdr->error = dnssd_htonl(n->Result);
+
+ data = rep->sdata;
+
+ *data++ = request->u.pm.NATinfo.ExternalAddress.b[0];
+ *data++ = request->u.pm.NATinfo.ExternalAddress.b[1];
+ *data++ = request->u.pm.NATinfo.ExternalAddress.b[2];
+ *data++ = request->u.pm.NATinfo.ExternalAddress.b[3];
+ *data++ = DNSServiceProtocol(request->u.pm.NATinfo.Protocol);
+ *data++ = request->u.pm.NATinfo.IntPort.b[0];
+ *data++ = request->u.pm.NATinfo.IntPort.b[1];
+ *data++ = request->u.pm.NATinfo.ExternalPort.b[0];
+ *data++ = request->u.pm.NATinfo.ExternalPort.b[1];
+ put_uint32(request->u.pm.NATinfo.Lifetime, &data);
+
+ LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT %.4a:%u TTL %u", request->sd,
+ DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+ mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
+ &request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort), request->u.pm.NATinfo.Lifetime);
+
+ append_reply(request, rep);
+ }
+
+mDNSlocal mStatus handle_port_mapping_request(request_state *request)
+ {
+ mDNSu32 ttl = 0;
+ mStatus err = mStatus_NoError;
- for (p = info->browsers; p; p = p->next)
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ mDNSu8 protocol = get_uint32(&request->msgptr, request->msgend);
+ (void)flags; // Unused
+ if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
+ if (request->msgptr + 8 > request->msgend) request->msgptr = NULL;
+ else
{
- if (SameDomainName(&p->domain, d))
- { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
+ request->u.pm.NATinfo.IntPort.b[0] = *request->msgptr++;
+ request->u.pm.NATinfo.IntPort.b[1] = *request->msgptr++;
+ request->u.pm.ReqExt.b[0] = *request->msgptr++;
+ request->u.pm.ReqExt.b[1] = *request->msgptr++;
+ ttl = get_uint32(&request->msgptr, request->msgend);
}
- b = mallocL("browser_t", sizeof(*b));
- if (!b) return mStatus_NoMemoryErr;
- AssignDomainName(&b->domain, d);
- err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
- if (err)
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceNATPortMappingCreate(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ if (protocol == 0) // If protocol == 0 (i.e. just request public address) then IntPort, ExtPort, ttl must be zero too
{
- LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
- freeL("browser_t", b);
+ if (!mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort) || !mDNSIPPortIsZero(request->u.pm.ReqExt) || ttl) return(mStatus_BadParamErr);
}
else
{
- b->next = info->browsers;
- info->browsers = b;
+ if (mDNSIPPortIsZero(request->u.pm.NATinfo.IntPort)) return(mStatus_BadParamErr);
+ if (!(protocol & (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP))) return(mStatus_BadParamErr);
}
- return err;
+
+ request->u.pm.NATinfo.Protocol = !protocol ? NATOp_AddrRequest : (protocol == kDNSServiceProtocol_UDP) ? NATOp_MapUDP : NATOp_MapTCP;
+ // u.pm.NATinfo.IntPort = already set above
+ request->u.pm.NATinfo.RequestedPort = request->u.pm.ReqExt;
+ request->u.pm.NATinfo.NATLease = ttl;
+ request->u.pm.NATinfo.clientCallback = port_mapping_create_request_callback;
+ request->u.pm.NATinfo.clientContext = request;
+
+ LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START", request->sd,
+ protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease);
+ err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
+ if (!err) request->terminate = port_mapping_termination_callback;
+
+ return(err);
}
-mDNSlocal void handle_browse_request(request_state *request)
- {
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- mDNSInterfaceID InterfaceID;
- char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
- domainname typedn, d, temp;
- mDNSs32 NumSubTypes;
- char *ptr;
- mStatus err = mStatus_NoError;
- DNameListElem *search_domain_list, *sdom;
- browser_info_t *info = NULL;
-
- if (request->ts != t_complete)
- {
- LogMsg("ERROR: handle_browse_request - transfer state != t_complete");
- abort_request(request);
- unlink_request(request);
- return;
- }
-
- // extract data from message
- ptr = request->msgdata;
- flags = get_flags(&ptr);
- interfaceIndex = get_long(&ptr);
- if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
- { err = mStatus_BadParamErr; goto error; }
- freeL("handle_browse_request", request->msgbuf);
- request->msgbuf = NULL;
-
- InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
- if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr; goto error; }
-
-#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
- if ( !domain || ( domain[0] == '\0' ) )
- {
- dDNS_RegisterSearchDomains( gmDNS );
- }
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - DNSServiceGetAddrInfo
#endif
-
- typedn.c[0] = 0;
- NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
- if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr; goto error; }
- if (NumSubTypes == 1 && !AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
- { err = mStatus_BadParamErr; goto error; }
-
- if (!regtype[0] || !AppendDNSNameString(&typedn, regtype)) { err = mStatus_BadParamErr; goto error; }
-
- if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { err = mStatus_BadParamErr; goto error; }
- if (temp.c[0] > 15 && domain[0] == 0) strcpy(domain, "local."); // For over-long service types, we only allow domain "local"
-
- // allocate and set up browser info
- info = mallocL("browser_info_t", sizeof(*info));
- if (!info) { err = mStatus_NoMemoryErr; goto error; }
-
- request->browser_info = info;
- info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
- info->interface_id = InterfaceID;
- AssignDomainName(&info->regtype, &typedn);
- info->rstate = request;
- info->default_domain = !domain[0];
- info->browsers = NULL;
-
- // setup termination context
- request->termination_context = info;
- request->terminate = browse_termination_callback;
-
- LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, info->regtype.c, domain);
- if (domain[0])
- {
- if (!MakeDomainNameFromDNSNameString(&d, domain)) { err = mStatus_BadParamErr; goto error; }
- err = add_domain_to_browser(info, &d);
- }
- else
+mDNSlocal void addrinfo_termination_callback(request_state *request)
+ {
+ if (request->u.addrinfo.q4.QuestionContext)
{
- search_domain_list = mDNSPlatformGetSearchDomainList();
- for (sdom = search_domain_list; sdom; sdom = sdom->next)
- {
- err = add_domain_to_browser(info, &sdom->name);
- if (err)
- {
- if (SameDomainName(&sdom->name, &localdomain)) break;
- else err = mStatus_NoError; // suppress errors for non-local "default" domains
- }
-
- }
- mDNS_FreeDNameList(search_domain_list);
+ mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
+ request->u.addrinfo.q4.QuestionContext = mDNSNULL;
}
-
- deliver_error(request, err);
- return;
-
-error:
- if (info) freeL("browser_info_t", info);
- if (request->termination_context) request->termination_context = NULL;
- deliver_error(request, err);
- abort_request(request);
- unlink_request(request);
- }
-
-mDNSlocal void browse_termination_callback(void *context)
- {
- browser_info_t *info = context;
- browser_t *ptr;
-
- if (!info) return;
- while(info->browsers)
+ if (request->u.addrinfo.q6.QuestionContext)
{
- ptr = info->browsers;
- info->browsers = ptr->next;
- LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->rstate->sd, ptr->q.qname.c);
- mDNS_StopBrowse(gmDNS, &ptr->q); // no need to error-check result
- freeL("browse_termination_callback", ptr);
+ mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
+ request->u.addrinfo.q6.QuestionContext = mDNSNULL;
}
-
- info->rstate->termination_context = NULL;
- freeL("browser_info", info);
}
-mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
+mDNSlocal mStatus handle_addrinfo_request(request_state *request)
{
- request_state *r;
+ char hostname[256];
+ domainname d;
+ mStatus err = 0;
+
+ DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+ mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ request->u.addrinfo.interface_id = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ if (interfaceIndex && !request->u.addrinfo.interface_id) return(mStatus_BadParamErr);
+ request->u.addrinfo.flags = flags;
+ request->u.addrinfo.protocol = get_uint32(&request->msgptr, request->msgend);
+ if (request->u.addrinfo.protocol > (kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6))
+ return(mStatus_BadParamErr);
+
+ if (get_string(&request->msgptr, request->msgend, hostname, 256) < 0) return(mStatus_BadParamErr);
+
+ if (!request->msgptr) { LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+
+ if (!MakeDomainNameFromDNSNameString(&d, hostname))
+ { LogMsg("ERROR: handle_addrinfo_request: bad hostname: %s", hostname); return(mStatus_BadParamErr); }
- for (r = all_requests; r; r = r->next)
+ if (!request->u.addrinfo.protocol)
{
- browser_info_t *info = r->browser_info;
-
- if (!info || !info->default_domain) continue;
- if (add) add_domain_to_browser(info, d);
+ NetworkInterfaceInfo *i;
+ if (IsLocalDomain(&d))
+ {
+ for (i = mDNSStorage.HostInterfaces; i; i = i->next)
+ {
+ if ((i->ip.type == mDNSAddrType_IPv4) && !mDNSIPv4AddressIsZero(i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
+ else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSIPv6AddressIsZero(i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
+ }
+ }
else
{
- browser_t **ptr = &info->browsers;
- while (*ptr)
+ for (i = mDNSStorage.HostInterfaces; i; i = i->next)
{
- if (SameDomainName(&(*ptr)->domain, d))
- {
- browser_t *remove = *ptr;
- *ptr = (*ptr)->next;
- if (remove->q.LongLived)
- {
- // give goodbyes for known answers.
- // note that since events are sent to client via udsserver_idle(), we don't need to worry about the question being cancelled mid-loop
- CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
- while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
- }
- mDNS_StopBrowse(gmDNS, &remove->q);
- freeL("browser_t", remove);
- return;
- }
- ptr = &(*ptr)->next;
+ if ((i->ip.type == mDNSAddrType_IPv4) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
+ else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
}
- LogMsg("Requested removal of default domain %##s not in list for sd %d", d->c, r->sd);
}
}
- }
-// Count how many other service records we have locally with the same name, but different rdata.
-// For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
-// the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
-mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
- {
- int count = 0;
- ResourceRecord *r = &srs->RR_SRV.resrec;
- AuthRecord *rr;
- ServiceRecordSet *s;
-
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
- count++;
+ if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
+ {
+ request->u.addrinfo.q4.InterfaceID = request->u.addrinfo.interface_id;
+ request->u.addrinfo.q4.Target = zeroAddr;
+ request->u.addrinfo.q4.qname = d;
+ request->u.addrinfo.q4.qtype = kDNSServiceType_A;
+ request->u.addrinfo.q4.qclass = kDNSServiceClass_IN;
+ request->u.addrinfo.q4.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
+ request->u.addrinfo.q4.ExpectUnique = mDNSfalse;
+ request->u.addrinfo.q4.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
+ request->u.addrinfo.q4.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ request->u.addrinfo.q4.QuestionCallback = queryrecord_result_callback;
+ request->u.addrinfo.q4.QuestionContext = request;
+
+ err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q4);
+ if (err != mStatus_NoError)
+ {
+ LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
+ request->u.addrinfo.q4.QuestionContext = mDNSNULL;
+ }
+ }
- for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
- if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
- count++;
+ if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6))
+ {
+ request->u.addrinfo.q6.InterfaceID = request->u.addrinfo.interface_id;
+ request->u.addrinfo.q6.Target = zeroAddr;
+ request->u.addrinfo.q6.qname = d;
+ request->u.addrinfo.q6.qtype = kDNSServiceType_AAAA;
+ request->u.addrinfo.q6.qclass = kDNSServiceClass_IN;
+ request->u.addrinfo.q6.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
+ request->u.addrinfo.q6.ExpectUnique = mDNSfalse;
+ request->u.addrinfo.q6.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
+ request->u.addrinfo.q6.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
+ request->u.addrinfo.q6.QuestionContext = request;
+
+ err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
+ if (err != mStatus_NoError)
+ {
+ LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
+ request->u.addrinfo.q6.QuestionContext = mDNSNULL;
+ }
+ }
- for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
- if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
- count++;
-
- verbosedebugf("%d peer registrations for %##s", count, r->name->c);
- return(count);
+ LogOperation("%3d: DNSServiceGetAddrInfo(%##s) START", request->sd, d.c);
+
+ if (!err) request->terminate = addrinfo_termination_callback;
+
+ return(err);
}
-mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Main Request Handler etc.
+#endif
+
+mDNSlocal request_state *NewRequest(void)
{
- int count = 0;
- AuthRecord *rr;
- for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.rrtype == kDNSType_SRV &&
- rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
- SameDomainName(rr->resrec.name, srv))
- count++;
- return(count);
+ request_state **p = &all_requests;
+ while (*p) p=&(*p)->next;
+ *p = mallocL("request_state", sizeof(request_state));
+ if (!*p) FatalError("ERROR: malloc");
+ mDNSPlatformMemZero(*p, sizeof(request_state));
+ return(*p);
}
-mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
+// read_msg may be called any time when the transfer state (req->ts) is t_morecoming.
+// returns the current state of the request (morecoming, error, complete, terminated.)
+// if there is no data on the socket, the socket will be closed and t_terminated will be returned
+// *** NOTE return value is actually ignored -- should change return type to void ***
+mDNSlocal int read_msg(request_state *req)
{
- service_info *info = request->service_registration;
- service_instance *ptr, *instance;
- int instance_size;
- mStatus result;
+ mDNSu32 nleft;
+ int nread;
- for (ptr = info->instances; ptr; ptr = ptr->next)
+ if (req->ts == t_terminated || req->ts == t_error)
{
- if (SameDomainName(&ptr->domain, domain))
- { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
+ LogMsg("ERROR: read_msg called with transfer state terminated or error");
+ req->ts = t_error;
+ return t_error;
}
-
- instance_size = sizeof(*instance);
- if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
- instance = mallocL("service_instance", instance_size);
- if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
- instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
- if (info->num_subtypes && !instance->subtypes)
- { free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
- instance->request = request;
- instance->sd = request->sd;
- instance->autoname = info->autoname;
- instance->autorename = info->autorename;
- instance->allowremotequery = info->allowremotequery;
- instance->rename_on_memfree = 0;
- instance->name = info->name;
- AssignDomainName(&instance->domain, domain);
- instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
- result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
- info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
-
- if (result) free_service_instance(instance);
- else
+ if (req->ts == t_complete) // this must be death or something is wrong
{
- instance->next = info->instances;
- info->instances = instance;
+ char buf[4]; // dummy for death notification
+ nread = recv(req->sd, buf, 4, 0);
+ if (!nread) { req->ts = t_terminated; return t_terminated; }
+ if (nread < 0) goto rerror;
+ LogMsg("ERROR: read data from a completed request.");
+ req->ts = t_error;
+ return t_error;
}
- return result;
- }
-mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
- {
- request_state *rstate;
- service_info *info;
+ if (req->ts != t_morecoming)
+ {
+ LogMsg("ERROR: read_msg called with invalid transfer state (%d)", req->ts);
+ req->ts = t_error;
+ return t_error;
+ }
- LogMsg("%s registration domain %##s", add ? "Adding" : "Removing", d->c);
- for (rstate = all_requests; rstate; rstate = rstate->next)
+ if (req->hdr_bytes < sizeof(ipc_msg_hdr))
{
- if (rstate->terminate != regservice_termination_callback) continue;
- info = rstate->service_registration;
- if (!info) { LogMsg("udsserver_default_reg_domain_changed - NULL service info"); continue; } // this should never happen
- if (!info->default_domain) continue;
+ nleft = sizeof(ipc_msg_hdr) - req->hdr_bytes;
+ nread = recv(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0);
+ if (nread == 0) { req->ts = t_terminated; return t_terminated; }
+ if (nread < 0) goto rerror;
+ req->hdr_bytes += nread;
+ if (req->hdr_bytes > sizeof(ipc_msg_hdr))
+ {
+ LogMsg("ERROR: read_msg - read too many header bytes");
+ req->ts = t_error;
+ return t_error;
+ }
- // valid default registration
- if (add) register_service_instance(rstate, d);
- else
+ // only read data if header is complete
+ if (req->hdr_bytes == sizeof(ipc_msg_hdr))
{
- // find the instance to remove
- service_instance *si = rstate->service_registration->instances, *prev = NULL;
- while (si)
+ ConvertHeaderBytes(&req->hdr);
+ if (req->hdr.version != VERSION)
+ { LogMsg("ERROR: client version 0x%08X daemon version 0x%08X", req->hdr.version, VERSION); req->ts = t_error; return t_error; }
+
+ // Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord()
+ // with 64kB of rdata. Adding 1005 byte for a maximal domain name, plus a safety margin
+ // for other overhead, this means any message above 70kB is definitely bogus.
+ if (req->hdr.datalen > 70000)
{
- if (SameDomainName(&si->domain, d))
- {
- mStatus err;
- if (prev) prev->next = si->next;
- else info->instances = si->next;
- err = mDNS_DeregisterService(gmDNS, &si->srs);
- if (err)
- {
- LogMsg("udsserver_default_reg_domain_changed - mDNS_DeregisterService err %d", err);
- free_service_instance(si);
- }
- break;
- }
- prev = si;
- si = si->next;
+ LogMsg("ERROR: read_msg - hdr.datalen %lu (%X) > 70000", req->hdr.datalen, req->hdr.datalen);
+ req->ts = t_error;
+ return t_error;
+ }
+ req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
+ if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return t_error; }
+ req->msgptr = req->msgbuf;
+ req->msgend = req->msgbuf + req->hdr.datalen;
+ mDNSPlatformMemZero(req->msgbuf, req->hdr.datalen + MSG_PAD_BYTES);
+ }
+ }
+
+ // If our header is complete, but we're still needing more body data, then try to read it now
+ // Note: For cancel_request req->hdr.datalen == 0, but there's no error return socket for cancel_request
+ // Any time we need to get the error return socket we know we'll have at least one data byte
+ // (even if only the one-byte empty C string placeholder for the old ctrl_path parameter)
+ if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes < req->hdr.datalen)
+ {
+ nleft = req->hdr.datalen - req->data_bytes;
+ struct iovec vec = { req->msgbuf + req->data_bytes, nleft }; // Tell recvmsg where we want the bytes put
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char cbuf[sizeof(struct cmsghdr) + sizeof(dnssd_sock_t)];
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
+ msg.msg_flags = 0;
+ nread = recvmsg(req->sd, &msg, 0);
+ if (nread == 0) { req->ts = t_terminated; return t_terminated; }
+ if (nread < 0) goto rerror;
+ req->data_bytes += nread;
+ if (req->data_bytes > req->hdr.datalen)
+ {
+ LogMsg("ERROR: read_msg - read too many data bytes");
+ req->ts = t_error;
+ return t_error;
+ }
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (msg.msg_controllen == sizeof(cbuf) &&
+ cmsg->cmsg_len == sizeof(cbuf) &&
+ cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS)
+ {
+ req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg);
+ if (req->data_bytes < req->hdr.datalen)
+ {
+ LogMsg("%3d: Client sent error socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
+ req->sd, req->errsd, req->data_bytes, req->hdr.datalen);
+ req->ts = t_error;
+ return t_error;
}
- if (!si) debugf("udsserver_default_reg_domain_changed - domain %##s not registered", d->c); // normal if registration failed
}
}
- }
-// service registration
-mDNSlocal void handle_regservice_request(request_state *request)
- {
- DNSServiceFlags flags;
- uint32_t ifi;
- char name[1024]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
- char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
- char *ptr;
- domainname d, srv;
- mStatus result;
- service_info *service = NULL;
+ // If our header and data are both complete, see if we need to make our separate error return socket
+ if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes == req->hdr.datalen)
+ {
+ if (req->terminate && req->hdr.op != cancel_request)
+ {
+ dnssd_sockaddr_t cliaddr;
+#if defined(USE_TCP_LOOPBACK)
+ mDNSOpaque16 port;
+ port.b[0] = req->msgptr[0];
+ port.b[1] = req->msgptr[1];
+ req->msgptr += 2;
+ cliaddr.sin_family = AF_INET;
+ cliaddr.sin_port = port.NotAnInteger;
+ cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+#else
+ char ctrl_path[MAX_CTLPATH];
+ get_string(&req->msgptr, req->msgend, ctrl_path, MAX_CTLPATH); // path is first element in message buffer
+ mDNSPlatformMemZero(&cliaddr, sizeof(cliaddr));
+ cliaddr.sun_family = AF_LOCAL;
+ mDNSPlatformStrCopy(cliaddr.sun_path, ctrl_path);
+ // If the error return path UDS name is empty string, that tells us
+ // that this is a new version of the library that's going to pass us
+ // the error return path socket via sendmsg/recvmsg
+ if (ctrl_path[0] == 0)
+ {
+ if (req->errsd == req->sd)
+ { LogMsg("%3d: request_callback: ERROR failed to get errsd via SCM_RIGHTS", req->sd); req->ts = t_error; return t_error; }
+ goto got_errfd;
+ }
+#endif
+
+ req->errsd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (!dnssd_SocketValid(req->errsd)) { my_perror("ERROR: socket"); req->ts = t_error; return t_error; }
- if (request->ts != t_complete)
- {
- LogMsg("ERROR: handle_regservice_request - transfer state != t_complete");
- abort_request(request);
- unlink_request(request);
- return;
- }
-
- service = mallocL("service_info", sizeof(*service));
- if (!service) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
-
- service->instances = NULL;
- service->request = request;
- service->txtlen = 0;
- service->txtdata = NULL;
- request->service_registration = service;
- request->termination_context = request->service_registration;
- request->terminate = regservice_termination_callback;
+ if (connect(req->errsd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
+ {
+#if !defined(USE_TCP_LOOPBACK)
+ struct stat sb;
+ LogMsg("request_callback: Couldn't connect to error return path socket “%s” errno %d %s",
+ cliaddr.sun_path, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+ if (stat(cliaddr.sun_path, &sb) < 0)
+ LogMsg("request_callback: stat failed “%s” errno %d %s", cliaddr.sun_path, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+ else
+ LogMsg("request_callback: file “%s” mode %o (octal) uid %d gid %d", cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
+#endif
+ req->ts = t_error;
+ return t_error;
+ }
- // extract data from message
- ptr = request->msgdata;
- flags = get_flags(&ptr);
- ifi = get_long(&ptr);
- service->InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
- if (ifi && !service->InterfaceID)
- { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
- if (get_string(&ptr, name, sizeof(name)) < 0 ||
- get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
- { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
-
- service->port.b[0] = *ptr++;
- service->port.b[1] = *ptr++;
-
- service->txtlen = get_short(&ptr);
- if (service->txtlen)
- {
- service->txtdata = mallocL("txtdata", service->txtlen);
- if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
- memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
- }
- else service->txtdata = NULL;
+got_errfd:
+ LogOperation("%3d: Using separate error socket %d", req->sd, req->errsd);
+#if defined(_WIN32)
+ if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0)
+#else
+ if (fcntl(req->errsd, F_SETFL, fcntl(req->errsd, F_GETFL, 0) | O_NONBLOCK) != 0)
+#endif
+ { my_perror("ERROR: could not set control socket to non-blocking mode"); req->ts = t_error; return t_error; }
+ }
+
+ req->ts = t_complete;
+ }
- // Check for sub-types after the service type
- service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes
- if (service->num_subtypes < 0)
- { LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", service->type_as_string); goto bad_param; }
+ return req->ts;
- // Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
- if (!*service->type_as_string || !MakeDomainNameFromDNSNameString(&service->type, service->type_as_string))
- { LogMsg("ERROR: handle_regservice_request - service->type_as_string bad %s", service->type_as_string); goto bad_param; }
+rerror:
+ if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
+ my_perror("ERROR: read_msg");
+ req->ts = t_error;
+ return t_error;
+ }
+
+#define RecordOrientedOp(X) \
+ ((X) == reg_record_request || (X) == add_record_request || (X) == update_record_request || (X) == remove_record_request)
+
+// The lightweight operations are the ones that don't need a dedicated request_state structure allocated for them
+#define LightweightOp(X) (RecordOrientedOp(X) || (X) == cancel_request)
+
+mDNSlocal void request_callback(int fd, short filter, void *info)
+ {
+ mStatus err = 0;
+ request_state *req = info;
+#if defined(_WIN32)
+ u_long opt = 1;
+#endif
+ mDNSs32 min_size = sizeof(DNSServiceFlags);
+ (void)fd; // Unused
+ (void)filter; // Unused
- if (!name[0])
+ read_msg(req);
+ if (req->ts == t_morecoming) return;
+ if (req->ts == t_terminated || req->ts == t_error) { AbortUnlinkAndFree(req); return; }
+
+ if (req->hdr.version != VERSION)
{
- service->name = (gmDNS)->nicelabel;
- service->autoname = mDNStrue;
+ LogMsg("ERROR: client incompatible with daemon (client version = %d, "
+ "daemon version = %d)\n", req->hdr.version, VERSION);
+ AbortUnlinkAndFree(req);
+ return;
}
- else
+
+ switch(req->hdr.op) // Interface + other data
{
- // If the client is allowing AutoRename, then truncate name to legal length before converting it to a DomainLabel
- if ((flags & kDNSServiceFlagsNoAutoRename) == 0)
+ case connection_request: min_size = 0; break;
+ case reg_service_request: min_size += sizeof(mDNSu32) + 4 /* name, type, domain, host */ + 4 /* port, textlen */; break;
+ case add_record_request: min_size += 4 /* type, rdlen */ + 4 /* ttl */; break;
+ case update_record_request: min_size += 2 /* rdlen */ + 4 /* ttl */; break;
+ case remove_record_request: break;
+ case browse_request: min_size += sizeof(mDNSu32) + 2 /* type, domain */; break;
+ case resolve_request: min_size += sizeof(mDNSu32) + 3 /* type, type, domain */; break;
+ case query_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 4 /* type, class*/; break;
+ case enumeration_request: min_size += sizeof(mDNSu32); break;
+ case reg_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */ + 4 /* ttl */; break;
+ case reconfirm_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */; break;
+ case setdomain_request: min_size += 1 /* domain */; break;
+ case getproperty_request: min_size = 2; break;
+ case port_mapping_request: min_size += sizeof(mDNSu32) + 4 /* udp/tcp */ + 4 /* int/ext port */ + 4 /* ttl */; break;
+ case addrinfo_request: min_size += sizeof(mDNSu32) + 4 /* v4/v6 */ + 1 /* hostname */; break;
+ case cancel_request: min_size = 0; break;
+ default: LogMsg("ERROR: validate_message - unsupported req type: %d", req->hdr.op); min_size = -1; break;
+ }
+
+ if ((mDNSs32)req->data_bytes < min_size)
+ { LogMsg("Invalid message %d bytes; min for %d is %d", req->data_bytes, req->hdr.op, min_size); AbortUnlinkAndFree(req); return; }
+
+ if (LightweightOp(req->hdr.op) && !req->terminate)
+ { LogMsg("Reg/Add/Update/Remove %d require existing connection", req->hdr.op); AbortUnlinkAndFree(req); return; }
+
+ // check if client wants silent operation
+ if (req->hdr.ipc_flags & IPC_FLAGS_NOREPLY) req->no_reply = 1;
+
+ // If req->terminate is already set, this means this operation is sharing an existing connection
+ if (req->terminate && !LightweightOp(req->hdr.op))
+ {
+ request_state *newreq = NewRequest();
+ newreq->primary = req;
+ newreq->sd = req->sd;
+ newreq->errsd = req->errsd;
+ newreq->uid = req->uid;
+ newreq->hdr = req->hdr;
+ newreq->msgbuf = req->msgbuf;
+ newreq->msgptr = req->msgptr;
+ newreq->msgend = req->msgend;
+ req = newreq;
+ }
+
+ switch(req->hdr.op)
+ {
+ // These are all operations that have their own first-class request_state object
+ case connection_request:
+ LogOperation("%3d: DNSServiceCreateConnection START", req->sd);
+ req->terminate = connection_termination;
+ break;
+ case resolve_request: err = handle_resolve_request (req); break;
+ case query_request: err = handle_queryrecord_request (req); break;
+ case browse_request: err = handle_browse_request (req); break;
+ case reg_service_request: err = handle_regservice_request (req); break;
+ case enumeration_request: err = handle_enum_request (req); break;
+ case reconfirm_record_request: err = handle_reconfirm_request (req); break;
+ case setdomain_request: err = handle_setdomain_request (req); break;
+ case getproperty_request: handle_getproperty_request (req); break;
+ case port_mapping_request: err = handle_port_mapping_request(req); break;
+ case addrinfo_request: err = handle_addrinfo_request (req); break;
+
+ // These are all operations that work with an existing request_state object
+ case reg_record_request: err = handle_regrecord_request (req); break;
+ case add_record_request: err = handle_add_request (req); break;
+ case update_record_request: err = handle_update_request (req); break;
+ case remove_record_request: err = handle_removerecord_request(req); break;
+ case cancel_request: handle_cancel_request (req); break;
+ default: LogMsg("%3d: ERROR: Unsupported UDS req: %d", req->sd, req->hdr.op);
+ }
+
+ // req->msgbuf may be NULL, e.g. for connection_request or remove_record_request
+ if (req->msgbuf) freeL("request_state msgbuf", req->msgbuf);
+
+ // There's no return data for a cancel request (DNSServiceRefDeallocate returns no result)
+ // For a DNSServiceGetProperty call, the handler already generated the response,
+ // so no need to do it again here
+ if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request)
+ {
+ err = dnssd_htonl(err);
+ send_all(req->errsd, (const char *)&err, sizeof(err));
+ if (req->errsd != req->sd)
{
- int newlen = TruncateUTF8ToLength((mDNSu8*)name, mDNSPlatformStrLen(name), MAX_DOMAIN_LABEL);
- name[newlen] = 0;
+ LogOperation("%3d: Closing error socket %d", req->sd, req->errsd);
+ dnssd_close(req->errsd);
+ req->errsd = req->sd;
+ // Also need to reset the parent's errsd, if this is a subbordinate operation
+ if (req->primary) req->primary->errsd = req->primary->sd;
}
- if (!MakeDomainLabelFromLiteralString(&service->name, name))
- { LogMsg("ERROR: handle_regservice_request - name bad %s", name); goto bad_param; }
- service->autoname = mDNSfalse;
}
-
- if (*domain)
+
+ // Reset ready to accept the next req on this pipe
+ if (req->primary) req = req->primary;
+ req->ts = t_morecoming;
+ req->hdr_bytes = 0;
+ req->data_bytes = 0;
+ req->msgbuf = mDNSNULL;
+ req->msgptr = mDNSNULL;
+ req->msgend = 0;
+ }
+
+mDNSlocal void connect_callback(int fd, short filter, void *info)
+ {
+ dnssd_sockaddr_t cliaddr;
+ dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
+ dnssd_sock_t sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len);
+ const unsigned long optval = 1;
+
+ (void)fd; // Unused
+ (void)filter; // Unused
+ (void)info; // Unused
+
+ if (!dnssd_SocketValid(sd))
{
- service->default_domain = mDNSfalse;
- if (!MakeDomainNameFromDNSNameString(&d, domain))
- { LogMsg("ERROR: handle_regservice_request - domain bad %s", domain); goto bad_param; }
+ if (dnssd_errno() != dnssd_EWOULDBLOCK) my_perror("ERROR: accept");
+ return;
}
- else
+
+#ifdef SO_NOSIGPIPE
+ // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
+ if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
{
- service->default_domain = mDNStrue;
- MakeDomainNameFromDNSNameString(&d, "local.");
+ my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
+ dnssd_close(sd);
+ return;
}
-
- if (!ConstructServiceName(&srv, &service->name, &service->type, &d))
- { LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”", service->name.c, service->type.c, d.c); goto bad_param; }
-
- if (!MakeDomainNameFromDNSNameString(&service->host, host))
- { LogMsg("ERROR: handle_regservice_request - host bad %s", host); goto bad_param; }
- service->autorename = (flags & kDNSServiceFlagsNoAutoRename ) == 0;
- service->allowremotequery = (flags & kDNSServiceFlagsAllowRemoteQuery) != 0;
-
- // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
- // a port number of zero. When two instances of the protected client are allowed to run on one
- // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
- if (service->port.NotAnInteger)
+#endif
+
+#if defined(_WIN32)
+ if (ioctlsocket(sd, FIONBIO, &optval) != 0)
+#else
+ if (fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK) != 0)
+#endif
{
- int count = CountExistingRegistrations(&srv, service->port);
- if (count)
- LogMsg("Client application registered %d identical instances of service %##s port %u.",
- count+1, srv.c, mDNSVal16(service->port));
+ my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
+ dnssd_close(sd);
+ return;
}
-
- LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START",
- request->sd, name, service->type_as_string, domain, host, mDNSVal16(service->port));
- result = register_service_instance(request, &d);
-
- if (!result && !*domain)
+ else
{
- DNameListElem *ptr, *def_domains = mDNSPlatformGetRegDomainList();
- for (ptr = def_domains; ptr; ptr = ptr->next)
- register_service_instance(request, &ptr->name);
- // note that we don't report errors for non-local, non-explicit domains
- mDNS_FreeDNameList(def_domains);
+ request_state *request = NewRequest();
+ request->ts = t_morecoming;
+ request->sd = sd;
+ request->errsd = sd;
+#if APPLE_OSX_mDNSResponder
+ struct xucred x;
+ socklen_t len = sizeof(x);
+ if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &len) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid;
+ else my_perror("ERROR: getsockopt, LOCAL_PEERCRED");
+ debugf("LOCAL_PEERCRED %d %u %u %d", len, x.cr_version, x.cr_uid, x.cr_ngroups);
+#endif APPLE_OSX_mDNSResponder
+ LogOperation("%3d: Adding FD for uid %u", request->sd, request->uid);
+ udsSupportAddFDToEventLoop(sd, request_callback, request);
}
-
-finish:
- deliver_error(request, result);
- if (result != mStatus_NoError)
- {
- abort_request(request);
- unlink_request(request);
- }
- else
- reset_connected_rstate(request); // prepare to receive add/remove messages
-
- return;
-
-bad_param:
- //if (service) freeL("service_info", service); Don't think we should do this -- abort_request will free it a second time and crash
- deliver_error(request, mStatus_BadParamErr);
- abort_request(request);
- unlink_request(request);
- }
+ }
-// service registration callback performs three duties - frees memory for deregistered services,
-// handles name conflicts, and delivers completed registration information to the client (via
-// process_service_registraion())
+mDNSexport int udsserver_init(dnssd_sock_t skt)
+ {
+ dnssd_sockaddr_t laddr;
+ int ret;
+#if defined(_WIN32)
+ u_long opt = 1;
+#endif
-mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
- {
- mStatus err;
- mDNSBool SuppressError = mDNSfalse;
- service_instance *instance = srs->ServiceContext;
- (void)m; // Unused
- if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
- if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
+ LogOperation("udsserver_init");
- if (instance->request && instance->request->service_registration)
+ // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
+ if (PID_FILE[0])
{
- service_info *info = instance->request->service_registration;
- if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
- // don't send errors up to client for wide-area, empty-string registrations
+ FILE *fp = fopen(PID_FILE, "w");
+ if (fp != NULL)
+ {
+ fprintf(fp, "%d\n", getpid());
+ fclose(fp);
+ }
}
-
- if (result == mStatus_NoError)
- LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
- else if (result == mStatus_MemFree)
- LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
- else if (result == mStatus_NameConflict)
- LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
- else
- LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
- if (result == mStatus_NoError)
+ if (dnssd_SocketValid(skt))
+ listenfd = skt;
+ else
{
- request_state *req = instance->request;
- if (instance->allowremotequery)
+ listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (!dnssd_SocketValid(listenfd))
{
- ExtraResourceRecord *e;
- srs->RR_ADV.AllowRemoteQuery = mDNStrue;
- srs->RR_PTR.AllowRemoteQuery = mDNStrue;
- srs->RR_SRV.AllowRemoteQuery = mDNStrue;
- srs->RR_TXT.AllowRemoteQuery = mDNStrue;
- for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
+ my_perror("ERROR: socket(AF_DNSSD, SOCK_STREAM, 0); failed");
+ goto error;
}
-
- if (!req) LogMsg("ERROR: regservice_callback - null request object");
- else
+
+ mDNSPlatformMemZero(&laddr, sizeof(laddr));
+
+ #if defined(USE_TCP_LOOPBACK)
{
- reply_state *rep;
- if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
- LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
- else
+ laddr.sin_family = AF_INET;
+ laddr.sin_port = htons(MDNS_TCP_SERVERPORT);
+ laddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+ ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
+ if (ret < 0)
{
- transfer_state send_result = send_msg(rep);
- if (send_result == t_error || send_result == t_terminated)
- { abort_request(req); unlink_request(req); freeL("reply_state", rep); }
- else if (send_result == t_complete) freeL("regservice_callback", rep);
- else append_reply(req, rep);
+ my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
+ goto error;
}
}
- if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
- RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
- return;
+ #else
+ {
+ mode_t mask = umask(0);
+ unlink(MDNS_UDS_SERVERPATH); //OK if this fails
+ laddr.sun_family = AF_LOCAL;
+ #ifndef NOT_HAVE_SA_LEN
+ // According to Stevens (section 3.2), there is no portable way to
+ // determine whether sa_len is defined on a particular platform.
+ laddr.sun_len = sizeof(struct sockaddr_un);
+ #endif
+ mDNSPlatformStrCopy(laddr.sun_path, MDNS_UDS_SERVERPATH);
+ ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
+ umask(mask);
+ if (ret < 0)
+ {
+ my_perror("ERROR: bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr)); failed");
+ goto error;
+ }
+ }
+ #endif
}
- else if (result == mStatus_MemFree)
- {
- if (instance->rename_on_memfree)
- {
- instance->rename_on_memfree = 0;
- instance->name = gmDNS->nicelabel;
- err = mDNS_RenameAndReregisterService(gmDNS, srs, &instance->name);
- if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
- // error should never happen - safest to log and continue
- }
- else
- {
- free_service_instance(instance);
- return;
- }
- }
- else if (result == mStatus_NameConflict)
- {
- if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
- {
- // On conflict for an autoname service, rename and reregister *all* autoname services
- IncrementLabelSuffix(&m->nicelabel, mDNStrue);
- m->MainCallback(m, mStatus_ConfigChanged);
- }
- else if (instance->autoname || instance->autorename)
- {
- mDNS_RenameAndReregisterService(gmDNS, srs, mDNSNULL);
- return;
- }
- else
- {
- request_state *rs = instance->request;
- if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
- free_service_instance(instance);
- if (!SuppressError && deliver_async_error(rs, reg_service_reply, result) < 0)
- {
- abort_request(rs);
- unlink_request(rs);
- }
- return;
- }
- }
- else
- {
- request_state *rs = instance->request;
- if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
- if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
- free_service_instance(instance);
- if (!SuppressError && deliver_async_error(rs, reg_service_reply, result) < 0)
- {
- abort_request(rs);
- unlink_request(rs);
- }
- return;
- }
- }
-mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
- {
- ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext;
- (void)m; //unused
-
- if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
-
- debugf("%##s: MemFree", rr->resrec.name->c);
- if (rr->resrec.rdata != &rr->rdatastorage)
- freeL("Extra RData", rr->resrec.rdata);
- freeL("ExtraResourceRecord", extra);
- }
+#if defined(_WIN32)
+ // SEH: do we even need to do this on windows?
+ // This socket will be given to WSAEventSelect which will automatically set it to non-blocking
+ if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
+#else
+ if (fcntl(listenfd, F_SETFL, fcntl(listenfd, F_GETFL, 0) | O_NONBLOCK) != 0)
+#endif
+ {
+ my_perror("ERROR: could not set listen socket to non-blocking mode");
+ goto error;
+ }
+
+ if (listen(listenfd, LISTENQ) != 0)
+ {
+ my_perror("ERROR: could not listen on listen socket");
+ goto error;
+ }
+
+ if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL))
+ {
+ my_perror("ERROR: could not add listen socket to event loop");
+ goto error;
+ }
+ else LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", listenfd);
-mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
+#if !defined(PLATFORM_NO_RLIMIT)
{
- ServiceRecordSet *srs = &instance->srs;
- ExtraResourceRecord *extra;
- mStatus result;
- int size;
-
- if (rdlen > sizeof(RDataBody)) size = rdlen;
- else size = sizeof(RDataBody);
-
- extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
- if (!extra)
- {
- my_perror("ERROR: malloc");
- return mStatus_NoMemoryErr;
- }
-
- bzero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
- extra->r.resrec.rrtype = rrtype;
- extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
- extra->r.resrec.rdlength = rdlen;
- memcpy(&extra->r.rdatastorage.u.data, rdata, rdlen);
-
- result = mDNS_AddRecordToService(gmDNS, srs , extra, &extra->r.rdatastorage, ttl);
- if (result) { freeL("ExtraResourceRecord", extra); return result; }
+ // Set maximum number of open file descriptors
+ #define MIN_OPENFILES 10240
+ struct rlimit maxfds, newfds;
- extra->ClientID = rstate->hdr.reg_index;
- return result;
+ // Due to bugs in OS X (<rdar://problem/2941095>, <rdar://problem/3342704>, <rdar://problem/3839173>)
+ // you have to get and set rlimits once before getrlimit will return sensible values
+ if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+ if (setrlimit(RLIMIT_NOFILE, &maxfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+
+ if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+ newfds.rlim_max = (maxfds.rlim_max > MIN_OPENFILES) ? maxfds.rlim_max : MIN_OPENFILES;
+ newfds.rlim_cur = (maxfds.rlim_cur > MIN_OPENFILES) ? maxfds.rlim_cur : MIN_OPENFILES;
+ if (newfds.rlim_max != maxfds.rlim_max || newfds.rlim_cur != maxfds.rlim_cur)
+ if (setrlimit(RLIMIT_NOFILE, &newfds) < 0) my_perror("ERROR: Unable to set maximum file descriptor limit");
+
+ if (getrlimit(RLIMIT_NOFILE, &maxfds) < 0) { my_perror("ERROR: Unable to get file descriptor limit"); return 0; }
+ debugf("maxfds.rlim_max %d", (long)maxfds.rlim_max);
+ debugf("maxfds.rlim_cur %d", (long)maxfds.rlim_cur);
}
+#endif
-mDNSlocal mStatus handle_add_request(request_state *rstate)
- {
- uint32_t ttl;
- uint16_t rrtype, rdlen;
- char *ptr, *rdata;
- mStatus result = mStatus_UnknownErr;
- DNSServiceFlags flags;
- service_info *srvinfo = rstate->service_registration;
- service_instance *i;
+ // We start a "LocalOnly" query looking for Automatic Browse Domain records.
+ // When Domain Enumeration in uDNS.c finds an "lb" record from the network, it creates a
+ // "LocalOnly" record, which results in our AutomaticBrowseDomainChange callback being invoked
+ mDNS_GetDomains(&mDNSStorage, &mDNSStorage.AutomaticBrowseDomainQ, mDNS_DomainTypeBrowseAutomatic,
+ mDNSNULL, mDNSInterface_LocalOnly, AutomaticBrowseDomainChange, mDNSNULL);
- if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
+ RegisterLocalOnlyDomainEnumPTR(&mDNSStorage, &localdomain, mDNS_DomainTypeRegistration); // Add "local" as recommended registration domain ("dns-sd -E")
+ RegisterLocalOnlyDomainEnumPTR(&mDNSStorage, &localdomain, mDNS_DomainTypeBrowse); // Add "local" as recommended browsing domain ("dns-sd -F")
+ AddAutoBrowseDomain(0, &localdomain); // Add "local" as automatic browsing domain
- ptr = rstate->msgdata;
- flags = get_flags(&ptr);
- rrtype = get_short(&ptr);
- rdlen = get_short(&ptr);
- rdata = get_rdata(&ptr, rdlen);
- ttl = get_long(&ptr);
-
- if (!ttl) ttl = DefaultTTLforRRType(rrtype);
+ udsserver_handle_configchange(&mDNSStorage);
+ return 0;
- LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd,
- (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype));
+error:
- for (i = srvinfo->instances; i; i = i->next)
- {
- result = add_record_to_service(rstate, i, rrtype, rdlen, rdata, ttl);
- if (result && i->default_local) break;
- else result = mStatus_NoError; // suppress non-local default errors
- }
-
- return(result);
- }
+ my_perror("ERROR: udsserver_init");
+ return -1;
+ }
-mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
+mDNSexport int udsserver_exit(dnssd_sock_t skt)
{
- int rdsize;
- RData *newrd;
- mStatus result;
-
- if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
- else rdsize = sizeof(RDataBody);
- newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
- if (!newrd) FatalError("ERROR: malloc");
- newrd->MaxRDLength = (mDNSu16) rdsize;
- memcpy(&newrd->u, rdata, rdlen);
+ // If the launching environment created no listening socket,
+ // that means we created it ourselves, so we should clean it up on exit
+ if (!dnssd_SocketValid(skt))
+ {
+ dnssd_close(listenfd);
+#if !defined(USE_TCP_LOOPBACK)
+ // Currently, we're unable to remove /var/run/mdnsd because we've changed to userid "nobody"
+ // to give up unnecessary privilege, but we need to be root to remove this Unix Domain Socket.
+ // It would be nice if we could find a solution to this problem
+ if (unlink(MDNS_UDS_SERVERPATH))
+ debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
+#endif
+ }
- // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
- // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
- // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
- if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
+ if (PID_FILE[0]) unlink(PID_FILE);
- result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
- if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("handle_update_request", newrd); }
- return result;
+ return 0;
}
-mDNSlocal mStatus handle_update_request(request_state *rstate)
- {
- uint16_t rdlen;
- char *ptr, *rdata;
- uint32_t ttl;
- mStatus result = mStatus_BadReferenceErr;
- service_info *srvinfo = rstate->service_registration;
- service_instance *i;
- AuthRecord *rr = NULL;
-
- // get the message data
- ptr = rstate->msgdata;
- get_flags(&ptr); // flags unused
- rdlen = get_short(&ptr);
- rdata = get_rdata(&ptr, rdlen);
- ttl = get_long(&ptr);
-
- if (rstate->reg_recs)
+mDNSlocal void LogClientInfo(mDNS *const m, request_state *req)
+ {
+ if (!req->terminate)
+ LogMsgNoIdent("%3d: No operation yet on this socket", req->sd);
+ else if (req->terminate == connection_termination)
{
- // update an individually registered record
- registered_record_entry *reptr;
- for (reptr = rstate->reg_recs; reptr; reptr = reptr->next)
- {
- if (reptr->key == rstate->hdr.reg_index)
- {
- result = update_record(reptr->rr, rdlen, rdata, ttl);
- goto end;
- }
- }
- result = mStatus_BadReferenceErr;
- goto end;
+ registered_record_entry *p;
+ LogMsgNoIdent("%3d: DNSServiceCreateConnection", req->sd);
+ for (p = req->u.reg_recs; p; p=p->next)
+ LogMsgNoIdent(" -> DNSServiceRegisterRecord %3d %s", p->key, ARDisplayString(m, p->rr));
}
-
- // update a record from a service record set
- if (!srvinfo) { result = mStatus_BadReferenceErr; goto end; }
- for (i = srvinfo->instances; i; i = i->next)
+ else if (req->terminate == regservice_termination_callback)
{
- if (rstate->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT;
- else
- {
- ExtraResourceRecord *e;
- for (e = i->srs.Extras; e; e = e->next)
- if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }
- }
-
- if (!rr) { result = mStatus_BadReferenceErr; goto end; }
- result = update_record(rr, rdlen, rdata, ttl);
- if (result && i->default_local) goto end;
- else result = mStatus_NoError; // suppress non-local default errors
+ service_instance *ptr;
+ for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
+ LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
}
+ else if (req->terminate == browse_termination_callback)
+ {
+ browser_t *blist;
+ for (blist = req->u.browser.browsers; blist; blist = blist->next)
+ LogMsgNoIdent("%3d: DNSServiceBrowse %##s", req->sd, blist->q.qname.c);
+ }
+ else if (req->terminate == resolve_termination_callback)
+ LogMsgNoIdent("%3d: DNSServiceResolve %##s", req->sd, req->u.resolve.qsrv.qname.c);
+ else if (req->terminate == queryrecord_termination_callback)
+ LogMsgNoIdent("%3d: DNSServiceQueryRecord %##s (%s)", req->sd, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype));
+ else if (req->terminate == enum_termination_callback)
+ LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, req->u.enumeration.q_all.qname.c);
+ else if (req->terminate == port_mapping_termination_callback)
+ LogMsgNoIdent("%3d: DNSServiceNATPortMapping %.4a %s%s Int %d Req %d Ext %d Req TTL %d Granted TTL %d",
+ req->sd,
+ &req->u.pm.NATinfo.ExternalAddress,
+ req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
+ req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
+ mDNSVal16(req->u.pm.NATinfo.IntPort),
+ mDNSVal16(req->u.pm.ReqExt),
+ mDNSVal16(req->u.pm.NATinfo.ExternalPort),
+ req->u.pm.NATinfo.NATLease,
+ req->u.pm.NATinfo.Lifetime);
+ else if (req->terminate == addrinfo_termination_callback)
+ LogMsgNoIdent("%3d: DNSServiceGetAddrInfo %s%s %##s", req->sd,
+ req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : " ",
+ req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : " ",
+ req->u.addrinfo.q4.qname.c);
+ else
+ LogMsgNoIdent("%3d: Unrecognized operation %p", req->sd, req->terminate);
+ }
-end:
- LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
- (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL,
- rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
+mDNSexport void udsserver_info(mDNS *const m)
+ {
+ mDNSs32 now = mDNS_TimeNow(m);
+ mDNSu32 CacheUsed = 0, CacheActive = 0;
+ mDNSu32 slot;
+ CacheGroup *cg;
+ CacheRecord *cr;
- return(result);
- }
-
-mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
- {
- (void)m; // Unused
- if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
- }
+ LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+ LogMsgNoIdent("------------ Cache -------------");
-mDNSlocal void free_service_instance(service_instance *srv)
- {
- request_state *rstate = srv->request;
- ExtraResourceRecord *e = srv->srs.Extras, *tmp;
-
- // clear pointers from parent struct
- if (rstate)
- {
- service_instance *ptr = rstate->service_registration->instances, *prev = NULL;
- while (ptr)
+ LogMsgNoIdent("Slt Q TTL if U Type rdlen");
+ for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+ for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
{
- if (ptr == srv)
+ CacheUsed++; // Count one cache entity for the CacheGroup object
+ for (cr = cg->members; cr; cr=cr->next)
{
- if (prev) prev->next = ptr->next;
- else rstate->service_registration->instances = ptr->next;
- break;
+ mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
+ NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)cr->resrec.InterfaceID;
+ CacheUsed++;
+ if (cr->CRActiveQuestion) CacheActive++;
+ LogMsgNoIdent("%3d %s%8ld %-6s%s %-6s%s",
+ slot,
+ cr->CRActiveQuestion ? "*" : " ",
+ remain,
+ info ? info->ifname : "-U-",
+ (cr->resrec.RecordType == kDNSRecordTypePacketNegative) ? "-" :
+ (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
+ DNSTypeName(cr->resrec.rrtype),
+ CRDisplayString(m, cr));
+ usleep(1000); // Limit rate a little so we don't flood syslog too fast
}
- prev = ptr;
- ptr = ptr->next;
}
- }
-
- while(e)
+
+ if (m->rrcache_totalused != CacheUsed)
+ LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
+ if (m->rrcache_active != CacheActive)
+ LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
+ LogMsgNoIdent("Cache currently contains %lu entities; %lu referenced by active questions", CacheUsed, CacheActive);
+
+ LogMsgNoIdent("--------- Auth Records ---------");
+ if (!m->ResourceRecords) LogMsgNoIdent("<None>");
+ else
{
- e->r.RecordContext = e;
- tmp = e;
- e = e->next;
- FreeExtraRR(gmDNS, &tmp->r, mStatus_MemFree);
+ AuthRecord *ar;
+ for (ar = m->ResourceRecords; ar; ar=ar->next)
+ LogMsgNoIdent("%s", ARDisplayString(m, ar));
}
-
- if (srv->subtypes) { freeL("regservice_callback", srv->subtypes); srv->subtypes = NULL; }
- freeL("regservice_callback", srv);
- }
-
-mDNSlocal void regservice_termination_callback(void *context)
- {
- service_info *info = context;
- service_instance *i, *p;
- if (!info) { LogMsg("regservice_termination_callback context is NULL"); return; }
- if (!info->request) { LogMsg("regservice_termination_callback info->request is NULL"); return; }
- i = info->instances;
- while (i)
- {
- p = i;
- i = i->next;
- p->request = NULL; // clear back pointer
- // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
- LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
- if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
- }
- info->request->service_registration = NULL; // clear pointer from request back to info
- if (info->txtdata) { freeL("txtdata", info->txtdata); info->txtdata = NULL; }
- freeL("service_info", info);
- }
-
-mDNSlocal mStatus handle_regrecord_request(request_state *rstate)
- {
- AuthRecord *rr;
- registered_record_entry *re;
- mStatus result;
-
- if (rstate->ts != t_complete)
- {
- LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
- abort_request(rstate);
- unlink_request(rstate);
- return(-1);
- }
-
- rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
- if (!rr) return(mStatus_BadParamErr);
-
- // allocate registration entry, link into list
- re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
- if (!re) FatalError("ERROR: malloc");
- re->key = rstate->hdr.reg_index;
- re->rr = rr;
- re->rstate = rstate;
- re->client_context = rstate->hdr.client_context;
- rr->RecordContext = re;
- rr->RecordCallback = regrecord_callback;
- re->next = rstate->reg_recs;
- rstate->reg_recs = re;
-
- if (!rstate->terminate)
- {
- rstate->terminate = connected_registration_termination;
- rstate->termination_context = rstate;
- }
-
- if (rr->resrec.rroriginalttl == 0)
- rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
-
- LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
- result = mDNS_Register(gmDNS, rr);
- return(result);
- }
-
-mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
- {
- registered_record_entry *re = rr->RecordContext;
- request_state *rstate = re ? re->rstate : NULL;
- int len;
- reply_state *reply;
- transfer_state ts;
- (void)m; // Unused
-
- if (!re)
- {
- // parent struct alreadt freed by termination callback
- if (!result) LogMsg("Error: regrecord_callback: successful registration of orphaned record");
- else
+
+ LogMsgNoIdent("---------- Questions -----------");
+ if (!m->Questions) LogMsgNoIdent("<None>");
+ else
+ {
+ DNSQuestion *q;
+ CacheUsed = 0;
+ CacheActive = 0;
+ LogMsgNoIdent(" Int Next if T NumAns Type Name");
+ for (q = m->Questions; q; q=q->next)
{
- if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
- freeL("regrecord_callback", rr);
+ mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
+ mDNSs32 n = (q->LastQTime + q->ThisQInterval - now) / mDNSPlatformOneSecond;
+ NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)q->InterfaceID;
+ CacheUsed++;
+ if (q->ThisQInterval) CacheActive++;
+ LogMsgNoIdent("%6d%6d %-6s%s %5d %-6s%##s%s",
+ i, n,
+ info ? info->ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
+ mDNSOpaque16IsZero(q->TargetQID) ? " " : q->LongLived ? "L" : "O", // mDNS, long-lived, or one-shot query?
+ q->CurrentAnswers,
+ DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
+ usleep(1000); // Limit rate a little so we don't flood syslog too fast
}
- return;
+ LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
}
-
- // format result, add to the list for the request, including the client context in the header
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t); //interfaceIndex
- len += sizeof(DNSServiceErrorType);
-
- reply = create_reply(reg_record_reply, len, rstate);
- reply->mhdr->client_context = re->client_context;
- reply->rhdr->flags = dnssd_htonl(0);
- reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID));
- reply->rhdr->error = dnssd_htonl(result);
-
- if (result)
- {
- // unlink from list, free memory
- registered_record_entry **ptr = &re->rstate->reg_recs;
- while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
- if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
- *ptr = (*ptr)->next;
- freeL("regrecord_callback", re->rr);
- re->rr = rr = NULL;
- freeL("regrecord_callback", re);
- re = NULL;
+
+ LogMsgNoIdent("---- Active Client Requests ----");
+ if (!all_requests) LogMsgNoIdent("<None>");
+ else
+ {
+ request_state *req;
+ for (req = all_requests; req; req=req->next)
+ LogClientInfo(m, req);
}
-
- ts = send_msg(reply);
-
- if (ts == t_error || ts == t_terminated) { abort_request(rstate); unlink_request(rstate); }
- else if (ts == t_complete) freeL("regrecord_callback", reply);
- else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list
- }
-
-mDNSlocal void connected_registration_termination(void *context)
- {
- int shared;
- registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
- while(ptr)
- {
- fptr = ptr;
- ptr = ptr->next;
- shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
- fptr->rr->RecordContext = NULL;
- mDNS_Deregister(gmDNS, fptr->rr);
- freeL("connected_registration_termination", fptr);
- }
- }
-
-mDNSlocal mStatus handle_removerecord_request(request_state *rstate)
- {
- mStatus err = mStatus_BadReferenceErr;
- char *ptr;
- service_info *srvinfo = rstate->service_registration;
-
- ptr = rstate->msgdata;
- get_flags(&ptr); // flags unused
-
- if (rstate->reg_recs) err = remove_record(rstate); // remove individually registered record
- else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
- else
+
+ LogMsgNoIdent("-------- NAT Traversals --------");
+ if (!m->NATTraversals) LogMsgNoIdent("<None>");
+ else
{
- service_instance *i;
- LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate->sd,
- (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL);
- for (i = srvinfo->instances; i; i = i->next)
+ NATTraversalInfo *nat;
+ for (nat = m->NATTraversals; nat; nat=nat->next)
{
- err = remove_extra(rstate, i);
- if (err && i->default_local) break;
- else err = mStatus_NoError; // suppress non-local default errors
+ if (nat->Protocol)
+ LogMsgNoIdent("%p %s Int %5d Ext %5d Err %d Retry %d Interval %d Expire %d",
+ nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP",
+ mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result,
+ nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
+ nat->retryInterval / mDNSPlatformOneSecond,
+ nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0);
+ else
+ LogMsgNoIdent("%p Address Request Retry %d Interval %d", nat,
+ (m->retryGetAddr - now) / mDNSPlatformOneSecond,
+ m->retryIntervalGetAddr / mDNSPlatformOneSecond);
}
}
-
- return(err);
- }
-// remove a resource record registered via DNSServiceRegisterRecord()
-mDNSlocal mStatus remove_record(request_state *rstate)
- {
- int shared;
- mStatus err = mStatus_UnknownErr;
- registered_record_entry *e, **ptr = &rstate->reg_recs;
-
- while(*ptr && (*ptr)->key != rstate->hdr.reg_index) ptr = &(*ptr)->next;
- if (!*ptr) { LogMsg("DNSServiceRemoveRecord - bad reference"); return mStatus_BadReferenceErr; }
- e = *ptr;
- *ptr = e->next; // unlink
-
- LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name->c);
- shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
- e->rr->RecordContext = NULL;
- err = mDNS_Deregister(gmDNS, e->rr);
- if (err)
+ LogMsgNoIdent("--------- AuthInfoList ---------");
+ if (!m->AuthInfoList) LogMsgNoIdent("<None>");
+ else
{
- LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err);
- freeL("remove_record", e->rr);
- freeL("remove_record", e);
+ DomainAuthInfo *a;
+ for (a = m->AuthInfoList; a; a = a->next)
+ LogMsgNoIdent("%##s %##s%s", a->domain.c, a->keyname.c, a->AutoTunnel ? " AutoTunnel" : "");
}
- return err;
- }
-
-mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv)
- {
- mStatus err = mStatus_BadReferenceErr;
- ExtraResourceRecord *ptr;
- for (ptr = serv->srs.Extras; ptr; ptr = ptr->next)
+ #if APPLE_OSX_mDNSResponder
+ LogMsgNoIdent("--------- TunnelClients ---------");
+ if (!m->TunnelClients) LogMsgNoIdent("<None>");
+ else
{
- if (ptr->ClientID == rstate->hdr.reg_index) // found match
- return mDNS_RemoveRecordFromService(gmDNS, &serv->srs, ptr, FreeExtraRR, ptr);
+ ClientTunnel *c;
+ for (c = m->TunnelClients; c; c = c->next)
+ LogMsgNoIdent("%##s local %.16a %.4a remote %.16a %.4a %5d interval %d", c->dstname.c, &c->loc_inner, &c->loc_outer, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), c->q.ThisQInterval);
}
- return err;
+ #endif
}
-// domain enumeration
-mDNSlocal void handle_enum_request(request_state *rstate)
- {
- DNSServiceFlags flags;
- uint32_t ifi;
- mDNSInterfaceID InterfaceID;
- char *ptr = rstate->msgdata;
- domain_enum_t *def, *all;
- enum_termination_t *term;
- mStatus err;
- int result;
-
- if (rstate->ts != t_complete)
- {
- LogMsg("ERROR: handle_enum_request - transfer state != t_complete");
- abort_request(rstate);
- unlink_request(rstate);
- return;
- }
-
- flags = get_flags(&ptr);
- ifi = get_long(&ptr);
- InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, ifi);
- if (ifi && !InterfaceID)
- {
- deliver_error(rstate, mStatus_BadParamErr);
- abort_request(rstate);
- unlink_request(rstate);
- return;
- }
-
- // allocate context structures
- def = mallocL("handle_enum_request", sizeof(domain_enum_t));
- all = mallocL("handle_enum_request", sizeof(domain_enum_t));
- term = mallocL("handle_enum_request", sizeof(enum_termination_t));
- if (!def || !all || !term) FatalError("ERROR: malloc");
-
-#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
- dDNS_RegisterSearchDomains( gmDNS );
-#endif
-
- // enumeration requires multiple questions, so we must link all the context pointers so that
- // necessary context can be reached from the callbacks
- def->rstate = rstate;
- all->rstate = rstate;
- term->def = def;
- term->all = all;
- term->rstate = rstate;
- rstate->termination_context = term;
- rstate->terminate = enum_termination_callback;
- def->question.QuestionContext = def;
- def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
- mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
- all->question.QuestionContext = all;
- all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
- mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
-
- // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
- if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
-
- // make the calls
- LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate->sd, flags,
- (flags & kDNSServiceFlagsBrowseDomains ) ? "kDNSServiceFlagsBrowseDomains" :
- (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
- err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
- if (err == mStatus_NoError)
- err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
- result = deliver_error(rstate, err); // send error *before* returning local domain
-
- if (result < 0 || err)
- {
- abort_request(rstate);
- unlink_request(rstate);
- return;
- }
- }
-
-mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
- {
- char domain[MAX_ESCAPED_DOMAIN_NAME];
- domain_enum_t *de = question->QuestionContext;
- DNSServiceFlags flags = 0;
- reply_state *reply;
- (void)m; // Unused
-
- if (answer->rrtype != kDNSType_PTR) return;
- if (!AddRecord && de->type != mDNS_DomainTypeBrowse) return;
-
- if (AddRecord)
- {
- flags |= kDNSServiceFlagsAdd;
- if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
- flags |= kDNSServiceFlagsDefault;
- }
- ConvertDomainNameToCString(&answer->rdata->u.name, domain);
- // note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
- // a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
- // network, so we just pass kDNSServiceInterfaceIndexAny
- reply = format_enumeration_reply(de->rstate, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
- if (!reply)
- {
- LogMsg("ERROR: enum_result_callback, format_enumeration_reply");
- return;
- }
- reply->next = NULL;
- append_reply(de->rstate, reply);
- return;
- }
-
-mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
- {
- size_t len;
- reply_state *reply;
- char *data;
-
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t);
- len += sizeof(DNSServiceErrorType);
- len += strlen(domain) + 1;
-
- reply = create_reply(enumeration_reply, len, rstate);
- reply->rhdr->flags = dnssd_htonl(flags);
- reply->rhdr->ifi = dnssd_htonl(ifi);
- reply->rhdr->error = dnssd_htonl(err);
- data = reply->sdata;
- put_string(domain, &data);
- return reply;
- }
-
-mDNSlocal void enum_termination_callback(void *context)
- {
- enum_termination_t *t = context;
- mDNS *coredata = gmDNS;
-
- mDNS_StopGetDomains(coredata, &t->all->question);
- mDNS_StopGetDomains(coredata, &t->def->question);
- freeL("enum_termination_callback", t->all);
- freeL("enum_termination_callback", t->def);
- t->rstate->termination_context = NULL;
- freeL("enum_termination_callback", t);
- }
-
-mDNSlocal void handle_reconfirm_request(request_state *rstate)
- {
- AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0);
- if (rr)
- {
- mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
- LogOperation(
- (status == mStatus_NoError) ?
- "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
- "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
- rstate->sd, RRDisplayString(gmDNS, &rr->resrec),
- mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status);
- status = 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger
- }
- abort_request(rstate);
- unlink_request(rstate);
- freeL("handle_reconfirm_request", rr);
- }
-
-// setup rstate to accept new reg/dereg requests
-mDNSlocal void reset_connected_rstate(request_state *rstate)
- {
- rstate->ts = t_morecoming;
- rstate->hdr_bytes = 0;
- rstate->data_bytes = 0;
- if (rstate->msgbuf) freeL("reset_connected_rstate", rstate->msgbuf);
- rstate->msgbuf = NULL;
- rstate->bufsize = 0;
- }
-
-// returns a resource record (allocated w/ malloc) containing the data found in an IPC message
-// data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
-// (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
-mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
- {
- char *rdata, name[256];
- AuthRecord *rr;
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- uint16_t type, class, rdlen;
- int storage_size;
-
- flags = get_flags(&msgbuf);
- if (validate_flags &&
- !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
- !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+mDNSexport void uds_validatelists(void)
+ {
+ request_state *req;
+ for (req = all_requests; req; req=req->next)
{
- LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
- return NULL;
- }
-
- interfaceIndex = get_long(&msgbuf);
- if (get_string(&msgbuf, name, 256) < 0)
- {
- LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
- return NULL;
- }
- type = get_short(&msgbuf);
- class = get_short(&msgbuf);
- rdlen = get_short(&msgbuf);
-
- if (rdlen > sizeof(RDataBody)) storage_size = rdlen;
- else storage_size = sizeof(RDataBody);
-
- rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
- if (!rr) FatalError("ERROR: malloc");
- bzero(rr, sizeof(AuthRecord)); // ok if oversized rdata not zero'd
-
- mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
- type, 0, (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), mDNSNULL, mDNSNULL);
-
- if (!MakeDomainNameFromDNSNameString(rr->resrec.name, name))
- {
- LogMsg("ERROR: bad name: %s", name);
- freeL("read_rr_from_ipc_msg", rr);
- return NULL;
- }
-
- if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
- rr->resrec.rrclass = class;
- rr->resrec.rdlength = rdlen;
- rr->resrec.rdata->MaxRDLength = rdlen;
- rdata = get_rdata(&msgbuf, rdlen);
- memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
- if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf);
- rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
- SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
- return rr;
- }
+ if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2))
+ LogMemCorruption("UDS request list: %p is garbage (%d)", req, req->sd);
-mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
- {
- domainlabel n;
- domainname d, t;
-
- if (!MakeDomainLabelFromLiteralString(&n, name)) return -1;
- if (!MakeDomainNameFromDNSNameString(&t, regtype)) return -1;
- if (!MakeDomainNameFromDNSNameString(&d, domain)) return -1;
- if (!ConstructServiceName(srv, &n, &t, &d)) return -1;
- return 0;
- }
-
-// append a reply to the list in a request object
-mDNSlocal void append_reply(request_state *req, reply_state *rep)
- {
- reply_state *ptr;
-
- if (!req->replies) req->replies = rep;
- else
- {
- ptr = req->replies;
- while (ptr->next) ptr = ptr->next;
- ptr->next = rep;
- }
- rep->next = NULL;
- }
-
-// read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
-// returns the current state of the request (morecoming, error, complete, terminated.)
-// if there is no data on the socket, the socket will be closed and t_terminated will be returned
-mDNSlocal int read_msg(request_state *rs)
- {
- uint32_t nleft;
- int nread;
- char buf[4]; // dummy for death notification
-
- if (rs->ts == t_terminated || rs->ts == t_error)
- {
- LogMsg("ERROR: read_msg called with transfer state terminated or error");
- rs->ts = t_error;
- return t_error;
- }
-
- if (rs->ts == t_complete)
- { // this must be death or something is wrong
- nread = recv(rs->sd, buf, 4, 0);
- if (!nread) { rs->ts = t_terminated; return t_terminated; }
- if (nread < 0) goto rerror;
- LogMsg("ERROR: read data from a completed request.");
- rs->ts = t_error;
- return t_error;
- }
-
- if (rs->ts != t_morecoming)
- {
- LogMsg("ERROR: read_msg called with invalid transfer state (%d)", rs->ts);
- rs->ts = t_error;
- return t_error;
- }
-
- if (rs->hdr_bytes < sizeof(ipc_msg_hdr))
- {
- nleft = sizeof(ipc_msg_hdr) - rs->hdr_bytes;
- nread = recv(rs->sd, (char *)&rs->hdr + rs->hdr_bytes, nleft, 0);
- if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
- if (nread < 0) goto rerror;
- rs->hdr_bytes += nread;
- if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
- {
- ConvertHeaderBytes(&rs->hdr);
- if (rs->hdr.version != VERSION)
- {
- LogMsg("ERROR: read_msg - client version 0x%08X does not match daemon version 0x%08X", rs->hdr.version, VERSION);
- rs->ts = t_error;
- return t_error;
- }
- }
- if (rs->hdr_bytes > sizeof(ipc_msg_hdr))
- {
- LogMsg("ERROR: read_msg - read too many header bytes");
- rs->ts = t_error;
- return t_error;
- }
- }
-
- // only read data if header is complete
- if (rs->hdr_bytes == sizeof(ipc_msg_hdr))
- {
- if (rs->hdr.datalen == 0) // ok in removerecord requests
- {
- rs->ts = t_complete;
- rs->msgbuf = NULL;
- return t_complete;
- }
-
- if (!rs->msgbuf) // allocate the buffer first time through
- {
- rs->msgbuf = mallocL("read_msg", rs->hdr.datalen + MSG_PAD_BYTES);
- if (!rs->msgbuf)
- {
- my_perror("ERROR: malloc");
- rs->ts = t_error;
- return t_error;
- }
- rs->msgdata = rs->msgbuf;
- bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
- }
- nleft = rs->hdr.datalen - rs->data_bytes;
- nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
- if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
- if (nread < 0) goto rerror;
- rs->data_bytes += nread;
- if (rs->data_bytes > rs->hdr.datalen)
- {
- LogMsg("ERROR: read_msg - read too many data bytes");
- rs->ts = t_error;
- return t_error;
- }
- }
-
- if (rs->hdr_bytes == sizeof(ipc_msg_hdr) && rs->data_bytes == rs->hdr.datalen)
- rs->ts = t_complete;
- else rs->ts = t_morecoming;
-
- return rs->ts;
+ reply_state *rep;
+ for (rep = req->replies; rep; rep=rep->next)
+ if (rep->next == (reply_state *)~0)
+ LogMemCorruption("UDS req->replies: %p is garbage", rep);
-rerror:
- if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
- my_perror("ERROR: read_msg");
- rs->ts = t_error;
- return t_error;
- }
-
-mDNSlocal int send_msg(reply_state *rs)
- {
- ssize_t nwriten;
-
- if (!rs->msgbuf)
- {
- LogMsg("ERROR: send_msg called with NULL message buffer");
- return t_error;
- }
-
- if (rs->request->no_reply) //!!!KRS this behavior should be optimized if it becomes more common
- {
- rs->ts = t_complete;
- freeL("send_msg", rs->msgbuf);
- return t_complete;
- }
-
- ConvertHeaderBytes(rs->mhdr);
- nwriten = send(rs->sd, rs->msgbuf + rs->nwriten, rs->len - rs->nwriten, 0);
- ConvertHeaderBytes(rs->mhdr);
- if (nwriten < 0)
- {
- if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
- else
- {
-#if !defined(PLATFORM_NO_EPIPE)
- if (dnssd_errno() == EPIPE)
- {
- debugf("%3d: broken pipe", rs->sd);
- rs->ts = t_terminated;
- rs->request->ts = t_terminated;
- return t_terminated;
- }
- else
-#endif
- {
- my_perror("ERROR: send\n");
- rs->ts = t_error;
- return t_error;
- }
- }
- }
- rs->nwriten += nwriten;
-
- if (rs->nwriten == rs->len)
- {
- rs->ts = t_complete;
- freeL("send_msg", rs->msgbuf);
- }
- return rs->ts;
- }
-
-mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
- {
- reply_state *reply;
- int totallen;
-
- if ((unsigned)datalen < sizeof(reply_hdr))
- {
- LogMsg("ERROR: create_reply - data length less than lenght of required fields");
- return NULL;
- }
-
- totallen = (int) (datalen + sizeof(ipc_msg_hdr));
- reply = mallocL("create_reply", sizeof(reply_state));
- if (!reply) FatalError("ERROR: malloc");
- bzero(reply, sizeof(reply_state));
- reply->ts = t_morecoming;
- reply->sd = request->sd;
- reply->request = request;
- reply->len = totallen;
- reply->msgbuf = mallocL("create_reply", totallen);
- if (!reply->msgbuf) FatalError("ERROR: malloc");
- bzero(reply->msgbuf, totallen);
- reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
- reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
- reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr);
- reply->mhdr->version = VERSION;
- reply->mhdr->op = op;
- reply->mhdr->datalen = totallen - sizeof(ipc_msg_hdr);
- return reply;
- }
-
-mDNSlocal int deliver_error(request_state *rstate, mStatus err)
- {
- int nwritten = -1;
- undelivered_error_t *undeliv;
-
- err = dnssd_htonl(err);
- nwritten = send(rstate->sd, (dnssd_sockbuf_t) &err, sizeof(mStatus), 0);
- if (nwritten < (int)sizeof(mStatus))
- {
- if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
- nwritten = 0;
- if (nwritten < 0)
+ if (req->terminate == connection_termination)
{
- my_perror("ERROR: send - unable to deliver error to client");
- return(-1);
+ registered_record_entry *p;
+ for (p = req->u.reg_recs; p; p=p->next)
+ if (p->next == (registered_record_entry *)~0)
+ LogMemCorruption("UDS req->u.reg_recs: %p is garbage", p);
}
- else
+ else if (req->terminate == regservice_termination_callback)
{
- //client blocked - store result and come backr
- undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
- if (!undeliv) FatalError("ERROR: malloc");
- undeliv->err = err;
- undeliv->nwritten = nwritten;
- undeliv->sd = rstate->sd;
- rstate->u_err = undeliv;
- return 0;
+ service_instance *p;
+ for (p = req->u.servicereg.instances; p; p=p->next)
+ if (p->next == (service_instance *)~0)
+ LogMemCorruption("UDS req->u.servicereg.instances: %p is garbage", p);
}
- }
- return 0;
- }
-
-// returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
-mDNSlocal transfer_state send_undelivered_error(request_state *rs)
- {
- int nwritten;
-
- nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
- if (nwritten < 0)
- {
- if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
- nwritten = 0;
- else
+ else if (req->terminate == browse_termination_callback)
{
- my_perror("ERROR: send - unable to deliver error to client\n");
- return t_error;
+ browser_t *p;
+ for (p = req->u.browser.browsers; p; p=p->next)
+ if (p->next == (browser_t *)~0)
+ LogMemCorruption("UDS req->u.browser.browsers: %p is garbage", p);
}
}
- if ((unsigned int)(nwritten + rs->u_err->nwritten) >= sizeof(mStatus))
- {
- freeL("send_undelivered_error", rs->u_err);
- rs->u_err = NULL;
- return t_complete;
- }
- rs->u_err->nwritten += nwritten;
- return t_morecoming;
- }
-
-// send bogus data along with an error code to the app callback
-// returns 0 on success (linking reply into list of not fully delivered),
-// -1 on failure (request should be aborted)
-mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
- {
- int len;
- reply_state *reply;
- transfer_state ts;
-
- if (rs->no_reply) return 0;
- len = 256; // long enough for any reply handler to read all args w/o buffer overrun
- reply = create_reply(op, len, rs);
- reply->rhdr->error = dnssd_htonl(err);
- ts = send_msg(reply);
- if (ts == t_error || ts == t_terminated)
- {
- freeL("deliver_async_error", reply);
- return -1;
- }
- else if (ts == t_complete) freeL("deliver_async_error", reply);
- else if (ts == t_morecoming) append_reply(rs, reply); // client is blocked, link reply into list
- return 0;
- }
-
-mDNSlocal void abort_request(request_state *rs)
- {
- reply_state *rep, *ptr;
-
- if (rs->terminate) rs->terminate(rs->termination_context); // terminate field may not be set yet
- if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
- LogOperation("%3d: Removing FD", rs->sd);
- udsSupportRemoveFDFromEventLoop(rs->sd); // Note: This also closes file descriptor rs->sd for us
- // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
- // for detecting when the memory for an object is inadvertently freed while the object is still on some list
- rs->sd = -2;
-
- // free pending replies
- rep = rs->replies;
- while(rep)
- {
- if (rep->msgbuf) freeL("abort_request", rep->msgbuf);
- ptr = rep;
- rep = rep->next;
- freeL("abort_request", ptr);
- }
-
- if (rs->u_err)
- {
- freeL("abort_request", rs->u_err);
- rs->u_err = NULL;
- }
- }
-
-mDNSlocal void unlink_request(request_state *rs)
- {
- request_state *ptr;
-
- if (rs == all_requests)
- {
- all_requests = all_requests->next;
- freeL("unlink_request", rs);
- return;
- }
- for(ptr = all_requests; ptr->next; ptr = ptr->next)
- if (ptr->next == rs)
- {
- ptr->next = rs->next;
- freeL("unlink_request", rs);
- return;
- }
- }
-
-//hack to search-replace perror's to LogMsg's
-mDNSlocal void my_perror(char *errmsg)
- {
- LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
- }
-
-// check that the message delivered by the client is sufficiently long to extract the required data from the buffer
-// without overrunning it.
-// returns 0 on success, -1 on error.
-
-mDNSlocal int validate_message(request_state *rstate)
- {
- uint32_t min_size;
-
- switch(rstate->hdr.op)
- {
- case resolve_request: min_size = sizeof(DNSServiceFlags) + // flags
- sizeof(uint32_t) + // interface
- (3 * sizeof(char)); // name, regtype, domain
- break;
- case query_request: min_size = sizeof(DNSServiceFlags) + // flags
- sizeof(uint32_t) + // interface
- sizeof(char) + // fullname
- (2 * sizeof(uint16_t)); // type, class
- break;
- case browse_request: min_size = sizeof(DNSServiceFlags) + // flags
- sizeof(uint32_t) + // interface
- (2 * sizeof(char)); // regtype, domain
- break;
- case reg_service_request: min_size = sizeof(DNSServiceFlags) + // flags
- sizeof(uint32_t) + // interface
- (4 * sizeof(char)) + // name, type, domain, host
- (2 * sizeof(uint16_t)); // port, textlen
- break;
- case enumeration_request: min_size = sizeof(DNSServiceFlags) + // flags
- sizeof(uint32_t); // interface
- break;
- case reg_record_request: min_size = sizeof(DNSServiceFlags) + // flags
- sizeof(uint32_t) + // interface
- sizeof(char) + // fullname
- (3 * sizeof(uint16_t)) + // type, class, rdlen
- sizeof(uint32_t); // ttl
- break;
- case add_record_request: min_size = sizeof(DNSServiceFlags) + // flags
- (2 * sizeof(uint16_t)) + // type, rdlen
- sizeof(uint32_t); // ttl
- break;
- case update_record_request: min_size = sizeof(DNSServiceFlags) + // flags
- sizeof(uint16_t) + // rdlen
- sizeof(uint32_t); // ttl
- break;
- case remove_record_request: min_size = sizeof(DNSServiceFlags); // flags
- break;
- case reconfirm_record_request: min_size=sizeof(DNSServiceFlags) + // flags
- sizeof(uint32_t) + // interface
- sizeof(char) + // fullname
- (3 * sizeof(uint16_t)); // type, class, rdlen
- break;
- case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char); // flags + domain
- break;
- default:
- LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);
- return -1;
- }
-
- return (rstate->data_bytes >= min_size ? 0 : -1);
-
- }
-
-mDNSlocal uint32_t dnssd_htonl(uint32_t l)
- {
- uint32_t ret;
- char * data;
+ DNameListElem *d;
+ for (d = SCPrefBrowseDomains; d; d=d->next)
+ if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
+ LogMemCorruption("SCPrefBrowseDomains: %p is garbage (%d)", d, d->name.c[0]);
- data = (char*) &ret;
+ ARListElem *b;
+ for (b = LocalDomainEnumRecords; b; b=b->next)
+ if (b->next == (ARListElem *)~0 || b->ar.resrec.name->c[0] > 63)
+ LogMemCorruption("LocalDomainEnumRecords: %p is garbage (%d)", b, b->ar.resrec.name->c[0]);
- put_long(l, &data);
+ for (d = AutoBrowseDomains; d; d=d->next)
+ if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
+ LogMemCorruption("AutoBrowseDomains: %p is garbage (%d)", d, d->name.c[0]);
- return ret;
+ for (d = AutoRegistrationDomains; d; d=d->next)
+ if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
+ LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]);
}
+#endif
-#if defined(_WIN32)
-
-mDNSlocal char * win32_strerror(int inErrorCode)
+mDNSlocal int send_msg(reply_state *rep)
{
- static char buffer[1024];
- DWORD n;
+ ssize_t nwriten;
+ if (!rep->msgbuf) { LogMsg("ERROR: send_msg called with NULL message buffer"); return(rep->ts = t_error); }
+ if (rep->request->no_reply) { freeL("reply_state msgbuf (no_reply)", rep->msgbuf); return(rep->ts = t_complete); }
- memset(buffer, 0, sizeof(buffer));
+ ConvertHeaderBytes(rep->mhdr);
+ nwriten = send(rep->sd, rep->msgbuf + rep->nwriten, rep->len - rep->nwriten, 0);
+ ConvertHeaderBytes(rep->mhdr);
- n = FormatMessageA(
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- (DWORD) inErrorCode,
- MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
- buffer,
- sizeof( buffer ),
- NULL );
+ if (nwriten < 0)
+ {
+ if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0;
+ else
+ {
+#if !defined(PLATFORM_NO_EPIPE)
+ if (dnssd_errno() == EPIPE)
+ return(rep->request->ts = rep->ts = t_terminated);
+ else
+#endif
+ {
+ LogMsg("send_msg ERROR: failed to write %d bytes to fd %d errno %d %s",
+ rep->len - rep->nwriten, rep->sd, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+ return(rep->ts = t_error);
+ }
+ }
+ }
+ rep->nwriten += nwriten;
+ if (rep->nwriten == rep->len) { freeL("reply_state msgbuf (t_complete)", rep->msgbuf); rep->ts = t_complete; }
+ return rep->ts;
+ }
+
+mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
+ {
+ mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
+ request_state **req = &all_requests;
- if( n > 0 )
+ while (*req)
{
- // Remove any trailing CR's or LF's since some messages have them.
+ while ((*req)->replies) // Send queued replies
+ {
+ transfer_state result;
+ if ((*req)->replies->next) (*req)->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing);
+ result = send_msg((*req)->replies); // Returns t_morecoming if buffer full because client is not reading
+ if (result == t_complete)
+ {
+ reply_state *fptr = (*req)->replies;
+ (*req)->replies = (*req)->replies->next;
+ freeL("reply_state/udsserver_idle", fptr);
+ (*req)->time_blocked = 0; // reset failure counter after successful send
+ continue;
+ }
+ else if (result == t_terminated || result == t_error) abort_request(*req);
+ break;
+ }
+
+ if ((*req)->replies) // If we failed to send everything, check our time_blocked timer
+ {
+ if (!(*req)->time_blocked) (*req)->time_blocked = NonZeroTime(now);
+ if (now - (*req)->time_blocked >= 60 * mDNSPlatformOneSecond)
+ {
+ LogMsg("Could not write data to client %d after %ld seconds - aborting connection",
+ (*req)->sd, (now - (*req)->time_blocked) / mDNSPlatformOneSecond);
+ LogClientInfo(&mDNSStorage, *req);
+ abort_request(*req);
+ }
+ else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;
+ }
- while( ( n > 0 ) && isspace( ( (unsigned char *) buffer)[ n - 1 ] ) )
+ if (!dnssd_SocketValid((*req)->sd)) // If this request is finished, unlink it from the list and free the memory
{
- buffer[ --n ] = '\0';
+ // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree()
+ request_state *tmp = *req;
+ *req = tmp->next;
+ freeL("request_state/udsserver_idle", tmp);
}
+ else
+ req = &(*req)->next;
}
-
- return buffer;
+ return nextevent;
}
-#endif
+struct CompileTimeAssertionChecks_uds_daemon
+ {
+ // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
+ // other overly-large structures instead of having a pointer to them, can inadvertently
+ // cause structure sizes (and therefore memory usage) to balloon unreasonably.
+ char sizecheck_request_state [(sizeof(request_state) <= 1800) ? 1 : -1];
+ char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 30) ? 1 : -1];
+ char sizecheck_service_instance [(sizeof(service_instance) <= 6000) ? 1 : -1];
+ char sizecheck_browser_t [(sizeof(browser_t) <= 1000) ? 1 : -1];
+ char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 20) ? 1 : -1];
+ char sizecheck_reply_state [(sizeof(reply_state) <= 40) ? 1 : -1];
+ };
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
File: uds_daemon.h
Change History (most recent first):
$Log: uds_daemon.h,v $
+Revision 1.24 2007/09/19 20:25:17 cheshire
+Deleted outdated comment
+
+Revision 1.23 2007/07/24 17:23:02 cheshire
+Rename DefRegList as AutoRegistrationDomains
+
+Revision 1.22 2007/07/11 02:58:04 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+
+Revision 1.21 2007/04/21 21:47:47 cheshire
+<rdar://problem/4376383> Daemon: Add watchdog timer
+
+Revision 1.20 2007/02/14 01:58:19 cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
+
+Revision 1.19 2007/02/07 19:32:00 cheshire
+<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
+
+Revision 1.18 2007/02/06 19:06:49 cheshire
+<rdar://problem/3956518> Need to go native with launchd
+
+Revision 1.17 2007/01/05 05:46:07 cheshire
+Add mDNS *const m parameter to udsserver_handle_configchange()
+
+Revision 1.16 2007/01/04 23:11:15 cheshire
+<rdar://problem/4720673> uDNS: Need to start caching unicast records
+When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
+
+Revision 1.15 2006/08/14 23:24:57 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.14 2005/01/27 17:48:39 cheshire
Added comment about CFSocketInvalidate closing the underlying socket
#include "mDNSEmbeddedAPI.h"
#include "dnssd_ipc.h"
-
/* Client interface: */
#define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
-extern int udsserver_init(void);
-
-// takes the next scheduled event time, does idle work, and returns the updated nextevent time
+extern int udsserver_init(dnssd_sock_t skt);
extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
-
extern void udsserver_info(mDNS *const m); // print out info about current state
-
-extern void udsserver_handle_configchange(void);
-
-extern int udsserver_exit(void); // should be called prior to app exit
-
-extern void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add);
-extern void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add);
+extern void udsserver_handle_configchange(mDNS *const m);
+extern int udsserver_exit(dnssd_sock_t skt); // should be called prior to app exit
/* Routines that uds_daemon expects to link against: */
-typedef void (*udsEventCallback)(void *context);
-
+typedef void (*udsEventCallback)(int fd, short filter, void *context);
extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context);
extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd); // Note: This also CLOSES the file descriptor as well
-// RecordUpdatedNiceLabel() can be a no-op on platforms that don't care about updating the machine's
-// global default service name (was OS X calls the "Computer Name") in response to name conflicts.
extern void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay);
// Globals and functions defined in uds_daemon.c and also shared with the old "daemon.c" on OS X
+
extern mDNS mDNSStorage;
+extern DNameListElem *AutoRegistrationDomains;
+extern DNameListElem *AutoBrowseDomains;
+
extern mDNSs32 ChopSubTypes(char *regtype);
extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p);
extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port);
extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result);
extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs);
+
+#if APPLE_OSX_mDNSResponder
+extern void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add);
+extern void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add);
+#endif
+
+extern const char mDNSResponderVersionString_SCCS[];
+#define mDNSResponderVersionString (mDNSResponderVersionString_SCCS+5)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSVxWorks.c,v $
+Revision 1.33 2007/03/22 18:31:48 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
+
+Revision 1.32 2006/12/19 22:43:56 cheshire
+Fix compiler warnings
+
+Revision 1.31 2006/11/10 00:54:16 cheshire
+<rdar://problem/4816598> Changing case of Computer Name doesn't work
+
+Revision 1.30 2006/08/14 23:25:18 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.29 2006/03/19 02:00:12 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
+
Revision 1.28 2005/05/30 07:36:38 bradley
New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
(void)sd; // Unused
}
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
{
(void)sd; // Unused
(void)buf; // Unused
return(0);
}
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
{
(void)sd; // Unused
(void)msg; // Unused
// mDNSPlatformStrCopy
//===========================================================================================================================
-void mDNSPlatformStrCopy( const void *inSrc, void *inDst )
+void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
{
check( inSrc );
check( inDst );
// mDNSPlatformMemCopy
//===========================================================================================================================
-void mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
+void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
{
check( inSrc );
check( inDst );
// mDNSPlatformMemSame
//===========================================================================================================================
-mDNSBool mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
+mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
{
check( inSrc );
check( inDst );
// mDNSPlatformInterfaceIDfromInterfaceIndex
//===========================================================================================================================
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS *const inMDNS, mDNSu32 inIndex )
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS *const inMDNS, mDNSu32 inIndex )
{
NetworkInterfaceInfoVxWorks * i;
// mDNSPlatformInterfaceIndexfromInterfaceID
//===========================================================================================================================
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS *const inMDNS, mDNSInterfaceID inID )
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS *const inMDNS, mDNSInterfaceID inID )
{
NetworkInterfaceInfoVxWorks * i;
// Update our globals and mDNS with the new labels.
- if( !SameDomainLabel( inMDNS->p->userNiceLabel.c, nicelabel.c ) )
+ if( !SameDomainLabelCS( inMDNS->p->userNiceLabel.c, nicelabel.c ) )
{
dmsg( kDebugLevelInfo, DEBUG_NAME "Updating nicelabel to \"%#s\"\n", nicelabel.c );
inMDNS->p->userNiceLabel = nicelabel;
inMDNS->nicelabel = nicelabel;
}
- if( !SameDomainLabel( inMDNS->p->userHostLabel.c, hostlabel.c ) )
+ if( !SameDomainLabelCS( inMDNS->p->userHostLabel.c, hostlabel.c ) )
{
dmsg( kDebugLevelInfo, DEBUG_NAME "Updating hostlabel to \"%#s\"\n", hostlabel.c );
inMDNS->p->userHostLabel = hostlabel;
// If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario.
flapping = ( ( inUTC - i->lastSeen ) > 0 ) && ( ( inUTC - i->lastSeen ) < 60 );
- mDNS_RegisterInterface( inMDNS, n, flapping ? mDNSPlatformOneSecond * 5 : 0 );
+ mDNS_RegisterInterface( inMDNS, n, flapping );
if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__,
i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip,
i->ifinfo.InterfaceActive ? " (Primary)" : "" );
- mDNS_DeregisterInterface( inMDNS, &i->ifinfo );
+ mDNS_DeregisterInterface( inMDNS, &i->ifinfo, mDNSfalse );
i->ifinfo.InterfaceID = NULL;
if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
}
struct ip_mreq mreqV4;
addrV4.s_addr = inAddr->ip.v4.NotAnInteger;
- mreqV4.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+ mreqV4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
mreqV4.imr_interface = addrV4;
err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqV4, sizeof( mreqV4 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
ifindex = inSS->info->scopeID;
mreqV6.ipv6mr_interface = ifindex;
- mreqV6.ipv6mr_multiaddr = *( (struct in6_addr * ) &AllDNSLinkGroupv6 );
+ mreqV6.ipv6mr_multiaddr = *( (struct in6_addr * ) &AllDNSLinkGroup_v6.ip.v6 );
err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqV6, sizeof( mreqV6 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSVxWorks.h,v $
+Revision 1.5 2006/08/14 23:25:18 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.4 2005/05/30 07:36:38 bradley
New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Contains: mDNS platform plugin for VxWorks.
Change History (most recent first):
$Log: mDNSVxWorksIPv4Only.c,v $
+Revision 1.31 2007/03/22 18:31:49 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
+
+Revision 1.30 2006/12/19 22:43:56 cheshire
+Fix compiler warnings
+
+Revision 1.29 2006/08/14 23:25:18 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.28 2006/03/19 02:00:12 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
+
Revision 1.27 2004/12/17 23:37:49 cheshire
<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
(and other repetitive configuration changes)
(void)sd; // Unused
}
-mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen)
+mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
{
(void)sd; // Unused
(void)buf; // Unused
return(0);
}
-mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len)
+mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
{
(void)sd; // Unused
(void)msg; // Unused
// mDNSPlatformStrCopy
//===========================================================================================================================
-void mDNSPlatformStrCopy( const void *inSrc, void *inDst )
+void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
{
check( inSrc );
check( inDst );
// mDNSPlatformMemCopy
//===========================================================================================================================
-void mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
+void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
{
check( inSrc );
check( inDst );
// mDNSPlatformMemSame
//===========================================================================================================================
-mDNSBool mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
+mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
{
check( inSrc );
check( inDst );
item->hostSet.Advertise = inMDNS->AdvertiseLocalAddresses;
item->hostSet.McastTxRx = mDNStrue;
- err = mDNS_RegisterInterface( inMDNS, &item->hostSet, 0 );
+ err = mDNS_RegisterInterface( inMDNS, &item->hostSet, mDNSfalse );
require_noerr( err, exit );
item->hostRegistered = mDNStrue;
if( inItem->hostRegistered )
{
inItem->hostRegistered = mDNSfalse;
- mDNS_DeregisterInterface( inMDNS, &inItem->hostSet );
+ mDNS_DeregisterInterface( inMDNS, &inItem->hostSet, mDNSfalse );
}
// Close the multicast socket.
// Join the all-DNS multicast group so we receive Multicast DNS packets.
ip.NotAnInteger = ipv4->sin_addr.s_addr;
- mreq.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+ mreq.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
mreq.imr_interface.s_addr = ip.NotAnInteger;
err = setsockopt( socketRef, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof( mreq ) );
check_errno( err, errno );
memset( &addr, 0, sizeof( addr ) );
addr.sin_family = AF_INET;
addr.sin_port = inPort.NotAnInteger;
- addr.sin_addr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+ addr.sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) );
check_errno( err, errno );
srcAddr.ip.v4.NotAnInteger = addr.sin_addr.s_addr;
srcPort.NotAnInteger = addr.sin_port;
dstAddr.type = mDNSAddrType_IPv4;
- dstAddr.ip.v4 = AllDNSLinkGroupv4;
+ dstAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
dstPort = MulticastDNSPort;
dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
// $$$ Non-Apple Platforms: Fill in appropriate name for device.
- mDNSPlatformStrCopy( kMDNSDefaultName, outName );
+ mDNSPlatformStrCopy( outName, kMDNSDefaultName );
}
//===========================================================================================================================
// $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
- mDNSPlatformStrCopy( kMDNSDefaultName, outName );
+ mDNSPlatformStrCopy( outName, kMDNSDefaultName );
}
#endif
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Contains: mDNS platform plugin for VxWorks.
Change History (most recent first):
$Log: mDNSVxWorksIPv4Only.h,v $
+Revision 1.4 2006/08/14 23:25:18 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2004/09/17 01:08:57 cheshire
Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
+++ /dev/null
-/*
- * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: CommonServices.h,v $
-Revision 1.3 2004/04/08 09:27:12 bradley
-Added macro for portable specification of callback calling conventions.
-
-Revision 1.2 2004/03/07 05:53:39 bradley
-Fixed NumVersion extraction macros. Updated error code mappings to match latest internal version.
-
-Revision 1.1 2004/01/30 02:25:59 bradley
-Common Services and portability support for various platforms.
-
-*/
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @header CommonServices
-
- Common Services for Mac OS X, Linux, Palm, VxWorks, Windows, and Windows CE.
-*/
-
-#ifndef __COMMON_SERVICES__
-#define __COMMON_SERVICES__
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#if 0
-#pragma mark == Target ==
-#endif
-
-//===========================================================================================================================
-// Target
-//===========================================================================================================================
-
-// Macintosh
-
-#if( !defined( TARGET_OS_MAC ) )
- #if( ( macintosh || __MACH__ ) && !KERNEL )
- // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
- #else
- #define TARGET_OS_MAC 0
- #endif
-#endif
-
-#if( !defined( TARGET_API_MAC_OSX_KERNEL ) )
- #if( __MACH__ && KERNEL )
- #define TARGET_API_MAC_OSX_KERNEL 1
- #else
- #define TARGET_API_MAC_OSX_KERNEL 0
- #endif
-#endif
-
-// Linux
-
-#if( !defined( TARGET_OS_LINUX ) )
- #if( defined( __linux__ ) )
- #define TARGET_OS_LINUX 1
- #else
- #define TARGET_OS_LINUX 0
- #endif
-#endif
-
-// Palm
-
-#if( !defined( TARGET_OS_PALM ) )
- #if( defined( __PALMOS_TRAPS__ ) || defined( __PALMOS_ARMLET__ ) )
- #define TARGET_OS_PALM 1
- #else
- #define TARGET_OS_PALM 0
- #endif
-#endif
-
-// VxWorks
-
-#if( !defined( TARGET_OS_VXWORKS ) )
-
- // No predefined macro for VxWorks so just assume VxWorks if nothing else is set.
-
- #if( !macintosh && !__MACH__ && !defined( __linux__ ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
- #define TARGET_OS_VXWORKS 1
- #else
- #define TARGET_OS_VXWORKS 0
- #endif
-#endif
-
-// Windows
-
-#if( !defined( TARGET_OS_WIN32 ) )
- #if( macintosh || __MACH__ )
- // ConditionalMacros.h in CoreServices will define this TARGET_* flag.
- #else
- #if( defined( _WIN32 ) )
- #define TARGET_OS_WIN32 1
- #else
- #define TARGET_OS_WIN32 0
- #endif
- #endif
-#endif
-
-// Windows CE
-
-#if( !defined( TARGET_OS_WINDOWS_CE ) )
- #if( defined( _WIN32_WCE ) )
- #define TARGET_OS_WINDOWS_CE 1
- #else
- #define TARGET_OS_WINDOWS_CE 0
- #endif
-#endif
-
-#if 0
-#pragma mark == Includes ==
-#endif
-
-//===========================================================================================================================
-// Includes
-//===========================================================================================================================
-
-#if( !KERNEL )
- #include <stddef.h>
-#endif
-
-#if( ( macintosh || __MACH__ ) && !KERNEL )
-
- #if( defined( __MWERKS__ ) )
- #if( __option( c9x ) )
- #include <stdbool.h>
- #endif
- #else
- #include <stdbool.h>
- #endif
-
- #include <stdint.h>
-
- #if( __MACH__ )
-
- // Mac OS X
-
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <fcntl.h>
- #include <pthread.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <unistd.h>
-
- #include <CoreServices/CoreServices.h>
-
- #else
-
- // Classic Mac OS
-
- #include <ConditionalMacros.h>
- #include <MacTypes.h>
-
- #endif
-
-#elif( KERNEL )
-
- // Mac OS X Kernel
-
- #include <stdint.h>
-
- #include <libkern/OSTypes.h>
- #include <sys/types.h>
-
-#elif( TARGET_OS_LINUX )
-
- // Linux (no special includes yet).
-
-#elif( TARGET_OS_PALM )
-
- // Palm (no special includes yet).
-
-#elif( TARGET_OS_VXWORKS )
-
- // VxWorks
-
- #include "vxWorks.h"
-
-#elif( TARGET_OS_WIN32 )
-
- // Windows
-
- #if( !defined( WIN32_WINDOWS ) )
- #define WIN32_WINDOWS 0x0401
- #endif
-
- #if( !defined( _WIN32_WINDOWS ) )
- #define _WIN32_WINDOWS 0x0401
- #endif
-
- #if( !defined( WIN32_LEAN_AND_MEAN ) )
- #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
- #endif
-
- #if( defined( __MWERKS__ ) )
-
- #if( __option( c9x ) )
- #include <stdbool.h>
- #endif
-
- #include <stdint.h>
-
- #elif( defined( _MSC_VER ) )
-
- #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
- #pragma warning( disable:4706 ) // Disable "assignment within conditional expression" for Microsoft headers.
-
- #endif
-
- #include <windows.h>
- #include <winsock2.h>
- #include <Ws2tcpip.h>
-
- #if( defined( _MSC_VER ) )
- #pragma warning( default:4706 )
- #endif
-
-#else
- #error unknown OS - update this file to support your OS
-#endif
-
-#if( !defined( TARGET_BUILD_MAIN ) )
- #if( !TARGET_OS_VXWORKS )
- #define TARGET_BUILD_MAIN 1
- #endif
-#endif
-
-#if( __GNUC__ || !TARGET_OS_VXWORKS )
- #define TARGET_LANGUAGE_C_LIKE 1
-#else
- #define TARGET_LANGUAGE_C_LIKE 0
-#endif
-
-#if 0
-#pragma mark == CPU ==
-#endif
-
-//===========================================================================================================================
-// CPU
-//===========================================================================================================================
-
-// PowerPC
-
-#if( !defined( TARGET_CPU_PPC ) )
- #if( defined( __ppc__ ) || defined( __PPC__ ) || defined( powerpc ) || defined( ppc ) || defined( _M_MPPC ) )
- #define TARGET_CPU_PPC 1
- #else
- #define TARGET_CPU_PPC 0
- #endif
-#endif
-
-// x86
-
-#if( !defined( TARGET_CPU_X86 ) )
- #if( __INTEL__ || defined( __i386__ ) || defined( i386 ) || defined( intel ) || defined( _M_IX86 ) )
- #define TARGET_CPU_X86 1
- #else
- #define TARGET_CPU_X86 0
- #endif
-#endif
-
-// MIPS
-
-#if( !defined( TARGET_CPU_MIPS ) )
- #if( __MIPS__ || defined( MIPS32 ) || defined( R3000 ) || defined( R4000 ) || defined( R4650 ) || defined( _M_MRX000 ) )
- #define TARGET_CPU_MIPS 1
- #else
- #define TARGET_CPU_MIPS 0
- #endif
-#endif
-
-#if( !defined( TARGET_CPU_PPC ) && !defined( TARGET_CPU_X86 ) && !defined( TARGET_CPU_MIPS ) )
- #error unknown CPU - update this file to support your CPU
-#endif
-
-#if 0
-#pragma mark == Byte Order ==
-#endif
-
-//===========================================================================================================================
-// Byte Order
-//===========================================================================================================================
-
-// TARGET_RT_LITTLE_ENDIAN
-
-#if( !defined( TARGET_RT_LITTLE_ENDIAN ) )
- #if( MIPSEL || IL_LITTLE_ENDIAN || defined( __LITTLE_ENDIAN__ ) || \
- ( defined( BYTE_ORDER ) && defined( LITTLE_ENDIAN ) && ( BYTE_ORDER == LITTLE_ENDIAN ) ) || \
- ( defined( _BYTE_ORDER ) && defined( _LITTLE_ENDIAN ) && ( _BYTE_ORDER == _LITTLE_ENDIAN ) ) || \
- ( defined( __BYTE_ORDER ) && defined( __LITTLE_ENDIAN ) && ( __BYTE_ORDER == __LITTLE_ENDIAN ) ) || \
- TARGET_CPU_X86 || ( defined( TARGET_RT_BIG_ENDIAN ) && !TARGET_RT_BIG_ENDIAN ) )
- #define TARGET_RT_LITTLE_ENDIAN 1
- #else
- #define TARGET_RT_LITTLE_ENDIAN 0
- #endif
-#endif
-
-// TARGET_RT_BIG_ENDIAN
-
-#if( !defined( TARGET_RT_BIG_ENDIAN ) )
- #if( MIPSEB || IL_BIG_ENDIAN || defined( __BIG_ENDIAN__ ) || \
- ( defined( BYTE_ORDER ) && defined( BIG_ENDIAN ) && ( BYTE_ORDER == BIG_ENDIAN ) ) || \
- ( defined( _BYTE_ORDER ) && defined( _BIG_ENDIAN ) && ( _BYTE_ORDER == _BIG_ENDIAN ) ) || \
- ( defined( __BYTE_ORDER ) && defined( __BIG_ENDIAN ) && ( __BYTE_ORDER == __BIG_ENDIAN ) ) || \
- ( defined( TARGET_RT_LITTLE_ENDIAN ) && !TARGET_RT_LITTLE_ENDIAN ) )
- #define TARGET_RT_BIG_ENDIAN 1
- #else
- #define TARGET_RT_BIG_ENDIAN 0
- #endif
-#endif
-
-#if( defined( TARGET_RT_LITTLE_ENDIAN ) && !defined( TARGET_RT_BIG_ENDIAN ) )
- #if( TARGET_RT_LITTLE_ENDIAN )
- #define TARGET_RT_BIG_ENDIAN 0
- #else
- #define TARGET_RT_BIG_ENDIAN 1
- #endif
-#endif
-
-#if( defined( TARGET_RT_BIG_ENDIAN ) && !defined( TARGET_RT_LITTLE_ENDIAN ) )
- #if( TARGET_RT_BIG_ENDIAN )
- #define TARGET_RT_LITTLE_ENDIAN 0
- #else
- #define TARGET_RT_LITTLE_ENDIAN 1
- #endif
-#endif
-
-#if( !defined( TARGET_RT_LITTLE_ENDIAN ) || !defined( TARGET_RT_BIG_ENDIAN ) )
- #error unknown byte order - update this file to support your byte order
-#endif
-
-// TARGET_RT_BYTE_ORDER
-
-#if( !defined( TARGET_RT_BYTE_ORDER_BIG_ENDIAN ) )
- #define TARGET_RT_BYTE_ORDER_BIG_ENDIAN 1234
-#endif
-
-#if( !defined( TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN ) )
- #define TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN 4321
-#endif
-
-#if( !defined( TARGET_RT_BYTE_ORDER ) )
- #if( TARGET_RT_LITTLE_ENDIAN )
- #define TARGET_RT_BYTE_ORDER TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN
- #else
- #define TARGET_RT_BYTE_ORDER TARGET_RT_BYTE_ORDER_BIG_ENDIAN
- #endif
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#if( !TARGET_OS_MAC )
- #define CR '\r'
-#endif
-
-#define LF '\n'
-#define CRSTR "\r"
-#define LFSTR "\n"
-#define CRLF "\r\n"
-#define CRCR "\r\r"
-
-#if 0
-#pragma mark == Compatibility ==
-#endif
-
-//===========================================================================================================================
-// Compatibility
-//===========================================================================================================================
-
-// Macros to allow the same code to work on Windows and other sockets API-compatible platforms.
-
-#if( TARGET_OS_WIN32 )
- #define close_compat( X ) closesocket( X )
- #define errno_compat() (int) GetLastError()
- #define set_errno_compat( X ) SetLastError( X )
- #define EWOULDBLOCK_compat WSAEWOULDBLOCK
- #define ETIMEDOUT_compat WSAETIMEDOUT
- #define ENOTCONN_compat WSAENOTCONN
- #define IsValidSocket( X ) ( ( X ) != INVALID_SOCKET )
- #define kInvalidSocketRef INVALID_SOCKET
- #if( TARGET_LANGUAGE_C_LIKE )
- typedef SOCKET SocketRef;
- #endif
-#else
- #define close_compat( X ) close( X )
- #define errno_compat() errno
- #define set_errno_compat( X ) do { errno = ( X ); } while( 0 )
- #define EWOULDBLOCK_compat EWOULDBLOCK
- #define ETIMEDOUT_compat ETIMEDOUT
- #define ENOTCONN_compat ENOTCONN
- #define IsValidSocket( X ) ( ( X ) >= 0 )
- #define kInvalidSocketRef -1
- #if( TARGET_LANGUAGE_C_LIKE )
- typedef int SocketRef;
- #endif
-#endif
-
-// socklen_t is not defined on the following platforms so emulate it if not defined:
-//
-// - Pre-Panther Mac OS X. Panther defines SO_NOADDRERR so trigger off that.
-// - Windows SDK prior to 2003. 2003+ SDK's define EAI_AGAIN so trigger off that.
-// - VxWorks
-
-#if( TARGET_LANGUAGE_C_LIKE )
- #if( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) || TARGET_OS_VXWORKS )
- typedef int socklen_t;
- #endif
-#endif
-
-// ssize_t is not defined on the following platforms so emulate it if not defined:
-//
-// - Mac OS X when not building with BSD headers
-// - Windows
-
-#if( TARGET_LANGUAGE_C_LIKE )
- #if( ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_VXWORKS )
- typedef int ssize_t;
- #endif
-#endif
-
-// sockaddr_storage is not supported on non-IPv6 machines so alias it to an IPv4-compatible structure.
-
-#if( TARGET_LANGUAGE_C_LIKE )
- #if( !defined( AF_INET6 ) )
- #define sockaddr_storage sockaddr_in
- #define ss_family sin_family
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined SOCKADDR_IS_IP_LOOPBACK
-
- @abstract Determines if a sockaddr is an IPv4 or IPv6 loopback address (if IPv6 is supported).
-*/
-
-#if( defined( AF_INET6 ) )
- #define SOCKADDR_IS_IP_LOOPBACK( SA ) \
- ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
- ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) \
- : ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET6 ) \
- ? IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) \
- : 0
-#else
- #define SOCKADDR_IS_IP_LOOPBACK( SA ) \
- ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
- ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) \
- : 0
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined SOCKADDR_IS_IP_LINK_LOCAL
-
- @abstract Determines if a sockaddr is an IPv4 or IPv6 link-local address (if IPv6 is supported).
-*/
-
-#if( defined( AF_INET6 ) )
- #define SOCKADDR_IS_IP_LINK_LOCAL( SA ) \
- ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
- ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
- ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
- : IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
-#else
- #define SOCKADDR_IS_IP_LINK_LOCAL( SA ) \
- ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
- ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
- ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
- : 0 )
-#endif
-
-// _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking
-// resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to
-// CreateThread on Windows CE.
-
-#if( TARGET_OS_WINDOWS_CE )
- #define _beginthreadex_compat( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR ) \
- (uintptr_t) CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS, \
- (LPDWORD) THREAD_ID_PTR )
-
- #define _endthreadex_compat( RESULT ) ExitThread( (DWORD) RESULT )
-#elif( TARGET_OS_WIN32 )
- #define _beginthreadex_compat _beginthreadex
- #define _endthreadex_compat _endthreadex
-#endif
-
-// The C99 "inline" keyword is not supported by Microsoft compilers, but they do support __inline so map it when needed.
-
-#if( defined( _MSC_VER ) )
- #define inline_compat __inline
-#else
- #define inline_compat inline
-#endif
-
-// Calling conventions
-
-#if( !defined( CALLBACK_COMPAT ) )
- #if( TARGET_OS_WIN32 || TARGET_OS_WINDOWS_CE )
- #define CALLBACK_COMPAT CALLBACK
- #else
- #define CALLBACK_COMPAT
- #endif
-#endif
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined kSizeCString
-
- @abstract A meta-value to pass to supported routines to indicate the size should be calculated with strlen.
-*/
-
-#define kSizeCString ( (size_t) -1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined sizeof_array
-
- @abstract Determines the number of elements in an array.
-*/
-
-#define sizeof_array( X ) ( sizeof( X ) / sizeof( X[ 0 ] ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined sizeof_element
-
- @abstract Determines the size of an array element.
-*/
-
-#define sizeof_element( X ) sizeof( X[ 0 ] )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined sizeof_string
-
- @abstract Determines the size of a constant C string, excluding the null terminator.
-*/
-
-#define sizeof_string( X ) ( sizeof( ( X ) ) - 1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined sizeof_field
-
- @abstract Determines the size of a field of a type.
-*/
-
-#define sizeof_field( TYPE, FIELD ) sizeof( ( ( (TYPE *) 0 )->FIELD ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function RoundUp
-
- @abstract Rounds X up to a multiple of Y.
-*/
-
-#define RoundUp( X, Y ) ( ( X ) + ( ( Y ) - ( ( X ) % ( Y ) ) ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function IsAligned
-
- @abstract Returns non-zero if X is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
-*/
-
-#define IsAligned( X, Y ) ( ( ( X ) & ( ( Y ) - 1 ) ) == 0 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function IsFieldAligned
-
- @abstract Returns non-zero if FIELD of type TYPE is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
-*/
-
-#define IsFieldAligned( X, TYPE, FIELD, Y ) IsAligned( ( (uintptr_t)( X ) ) + offsetof( TYPE, FIELD ), ( Y ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function AlignDown
-
- @abstract Aligns X down to a Y byte boundary. Y must be a power of 2.
-*/
-
-#define AlignDown( X, Y ) ( ( X ) & ~( ( Y ) - 1 ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function AlignUp
-
- @abstract Aligns X up to a Y byte boundary. Y must be a power of 2.
-*/
-
-#define AlignUp( X, Y ) ( ( ( X ) + ( ( Y ) - 1 ) ) & ~( ( Y ) - 1 ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function Min
-
- @abstract Returns the lesser of X and Y.
-*/
-
-#if( !defined( Min ) )
- #define Min( X, Y ) ( ( ( X ) < ( Y ) ) ? ( X ) : ( Y ) )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function Max
-
- @abstract Returns the greater of X and Y.
-*/
-
-#if( !defined( Max ) )
- #define Max( X, Y ) ( ( ( X ) > ( Y ) ) ? ( X ) : ( Y ) )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function InsertBits
-
- @abstract Inserts BITS (both 0 and 1 bits) into X, controlled by MASK and SHIFT, and returns the result.
-
- @discussion
-
- MASK is the bitmask of the bits in the final position.
- SHIFT is the number of bits to shift left for 1 to reach the first bit position of MASK.
-
- For example, if you wanted to insert 0x3 into the leftmost 4 bits of a 32-bit value:
-
- InsertBits( 0, 0x3, 0xF0000000U, 28 ) == 0x30000000
-*/
-
-#define InsertBits( X, BITS, MASK, SHIFT ) ( ( ( X ) & ~( MASK ) ) | ( ( ( BITS ) << ( SHIFT ) ) & ( MASK ) ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function ExtractBits
-
- @abstract Extracts bits from X, controlled by MASK and SHIFT, and returns the result.
-
- @discussion
-
- MASK is the bitmask of the bits in the final position.
- SHIFT is the number of bits to shift right to right justify MASK.
-
- For example, if you had a 32-bit value (e.g. 0x30000000) wanted the left-most 4 bits (e.g. 3 in this example):
-
- ExtractBits( 0x30000000U, 0xF0000000U, 28 ) == 0x3
-*/
-
-#define ExtractBits( X, MASK, SHIFT ) ( ( ( X ) >> ( SHIFT ) ) & ( ( MASK ) >> ( SHIFT ) ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function Stringify
-
- @abstract Stringify's an expression.
-
- @discussion
-
- Stringify macros to process raw text passed via -D options to C string constants. The double-wrapping is necessary
- because the C preprocessor doesn't perform its normal argument expansion pre-scan with stringified macros so the
- -D macro needs to be expanded once via the wrapper macro then stringified so the raw text is stringified. Otherwise,
- the replacement value would be used instead of the symbolic name (only for preprocessor symbols like #defines).
-
- For example:
-
- #define kMyConstant 1
-
- printf( "%s", Stringify( kMyConstant ) ); // Prints "kMyConstant"
- printf( "%s", StringifyExpansion( kMyConstant ) ); // Prints "1"
-
- Non-preprocessor symbols do not have this issue. For example:
-
- enum
- {
- kMyConstant = 1
- };
-
- printf( "%s", Stringify( kMyConstant ) ); // Prints "kMyConstant"
- printf( "%s", StringifyExpansion( kMyConstant ) ); // Prints "kMyConstant"
-
- See <http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html> for more info on C preprocessor pre-scanning.
-*/
-
-#define Stringify( X ) # X
-#define StringifyExpansion( X ) Stringify( X )
-
-#if 0
-#pragma mark == Types ==
-#endif
-
-#if( TARGET_LANGUAGE_C_LIKE )
-//===========================================================================================================================
-// Standard Types
-//===========================================================================================================================
-
-#if( !defined( INT8_MIN ) )
-
- #define INT8_MIN SCHAR_MIN
-
- #if( defined( _MSC_VER ) )
-
- // C99 stdint.h not supported in VC++/VS.NET yet.
-
- typedef INT8 int8_t;
- typedef UINT8 uint8_t;
- typedef INT16 int16_t;
- typedef UINT16 uint16_t;
- typedef INT32 int32_t;
- typedef UINT32 uint32_t;
- typedef __int64 int64_t;
- typedef unsigned __int64 uint64_t;
-
- #elif( TARGET_OS_VXWORKS && ( TORNADO_VERSION < 220 ) )
- typedef long long int64_t;
- typedef unsigned long long uint64_t;
- #endif
-
- typedef int8_t int_least8_t;
- typedef int16_t int_least16_t;
- typedef int32_t int_least32_t;
- typedef int64_t int_least64_t;
-
- typedef uint8_t uint_least8_t;
- typedef uint16_t uint_least16_t;
- typedef uint32_t uint_least32_t;
- typedef uint64_t uint_least64_t;
-
- typedef int8_t int_fast8_t;
- typedef int16_t int_fast16_t;
- typedef int32_t int_fast32_t;
- typedef int64_t int_fast64_t;
-
- typedef uint8_t uint_fast8_t;
- typedef uint16_t uint_fast16_t;
- typedef uint32_t uint_fast32_t;
- typedef uint64_t uint_fast64_t;
-
- #if( !defined( _MSC_VER ) || TARGET_OS_WINDOWS_CE )
- typedef long int intptr_t;
- typedef unsigned long int uintptr_t;
- #endif
-
-#endif
-
-// Macros for minimum-width integer constants
-
-#if( !defined( INT8_C ) )
- #define INT8_C( value ) value
-#endif
-
-#if( !defined( INT16_C ) )
- #define INT16_C( value ) value
-#endif
-
-#if( !defined( INT32_C ) )
- #define INT32_C( value ) value ## L
-#endif
-
-#if( !defined( INT64_C ) )
- #if( defined( _MSC_VER ) )
- #define INT64_C( value ) value ## i64
- #else
- #define INT64_C( value ) value ## LL
- #endif
-#endif
-
-#if( !defined( UINT8_C ) )
- #define UINT8_C( value ) value ## U
-#endif
-
-#if( !defined( UINT16_C ) )
- #define UINT16_C( value ) value ## U
-#endif
-
-#if( !defined( UINT32_C ) )
- #define UINT32_C( value ) value ## UL
-#endif
-
-#if( !defined( UINT64_C ) )
- #if( defined( _MSC_VER ) )
- #define UINT64_C( value ) value ## UI64
- #else
- #define UINT64_C( value ) value ## ULL
- #endif
-#endif
-
-#if 0
-#pragma mark == bool ==
-#endif
-
-//===========================================================================================================================
-// Boolean Constants and Types
-//===========================================================================================================================
-
-// C++ defines bool, true, and false. Metrowerks allows this to be controlled by the "bool" option though.
-// C99 defines __bool_true_false_are_defined when bool, true, and false are defined.
-// MacTypes.h defines true and false (Mac builds only).
-//
-// Note: The Metrowerks has to be in its own block because Microsoft Visual Studio .NET does not completely
-// short-circuit and gets confused by the option( bool ) portion of the conditional.
-
-#if( defined( __MWERKS__ ) )
-
- // Note: The following test is done on separate lines because CodeWarrior doesn't like it all on one line.
-
- #if( !__bool_true_false_are_defined && ( !defined( __cplusplus ) || !__option( bool ) ) )
- #define COMMON_SERVICES_NEEDS_BOOL 1
- #else
- #define COMMON_SERVICES_NEEDS_BOOL 0
- #endif
-
- // Workaround when building with CodeWarrior, but using the Apple stdbool.h header, which uses _Bool.
-
- #if( __bool_true_false_are_defined && !defined( __cplusplus ) && !__option( c9x ) )
- #define _Bool int
- #endif
-
- // Workaround when building with CodeWarrior for C++ with bool disabled and using the Apple stdbool.h header,
- // which defines true and false to map to C++ true and false (which are not enabled). Serenity Now!
-
- #if( __bool_true_false_are_defined && defined( __cplusplus ) && !__option( bool ) )
- #define true 1
- #define false 0
- #endif
-#else
- #define COMMON_SERVICES_NEEDS_BOOL ( !defined( __cplusplus ) && !__bool_true_false_are_defined )
-#endif
-
-#if( COMMON_SERVICES_NEEDS_BOOL )
-
- typedef int bool;
-
- #define bool bool
-
- #if( !defined( __MACTYPES__ ) && !defined( true ) && !defined( false ) )
- #define true 1
- #define false 0
- #endif
-
- #define __bool_true_false_are_defined 1
-#endif
-
-// IOKit IOTypes.h typedef's bool if TYPE_BOOL is not defined so define it here to prevent redefinition by IOTypes.h.
-
-#if( TARGET_API_MAC_OSX_KERNEL )
- #define TYPE_BOOL 1
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef CStr255
-
- @abstract 255 character null-terminated (C-style) string.
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
- typedef char CStr255[ 256 ];
-#endif
-
-#endif // TARGET_LANGUAGE_C_LIKE
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined TYPE_LONGLONG_NATIVE
-
- @abstract Defines whether long long (or its equivalent) is natively supported or requires special libraries.
-*/
-
-#if( !defined( TYPE_LONGLONG_NATIVE ) )
- #if( !TARGET_OS_VXWORKS )
- #define TYPE_LONGLONG_NATIVE 1
- #else
- #define TYPE_LONGLONG_NATIVE 0
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined long_long_compat
-
- @abstract Compatibility type to map to the closest thing to long long and unsigned long long.
-
- @discussion
-
- Neither long long nor unsigned long long are supported by Microsoft compilers, but they do support proprietary
- "__int64" and "unsigned __int64" equivalents so map to those types if the real long long is not supported.
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
- #if( TARGET_OS_WIN32 )
- typedef __int64 long_long_compat;
- typedef unsigned __int64 unsigned_long_long_compat;
- #else
- typedef signed long long long_long_compat;
- typedef unsigned long long unsigned_long_long_compat;
- #endif
-#endif
-
-#if 0
-#pragma mark == Errors ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum OSStatus
-
- @abstract Status Code
-
- @constant kNoErr 0 No error occurred.
- @constant kInProgressErr 1 Operation in progress.
- @constant kUnknownErr -6700 Unknown error occurred.
- @constant kOptionErr -6701 Option was not acceptable.
- @constant kSelectorErr -6702 Selector passed in is invalid or unknown.
- @constant kExecutionStateErr -6703 Call made in the wrong execution state (e.g. called at interrupt time).
- @constant kPathErr -6704 Path is invalid, too long, or otherwise not usable.
- @constant kParamErr -6705 Parameter is incorrect, missing, or not appropriate.
- @constant kParamCountErr -6706 Incorrect or unsupported number of parameters.
- @constant kCommandErr -6707 Command invalid or not supported.
- @constant kIDErr -6708 Unknown, invalid, or inappropriate identifier.
- @constant kStateErr -6709 Not in appropriate state to perform operation.
- @constant kRangeErr -6710 Index is out of range or not valid.
- @constant kRequestErr -6711 Request was improperly formed or not appropriate.
- @constant kResponseErr -6712 Response was incorrect or out of sequence.
- @constant kChecksumErr -6713 Checksum does not match the actual data.
- @constant kNotHandledErr -6714 Operation was not handled (or not handled completely).
- @constant kVersionErr -6715 Version is not incorrect or not compatibile.
- @constant kSignatureErr -6716 Signature did not match what was expected.
- @constant kFormatErr -6717 Unknown, invalid, or inappropriate file/data format.
- @constant kNotInitializedErr -6718 Action request before needed services were initialized.
- @constant kAlreadyInitializedErr -6719 Attempt made to initialize when already initialized.
- @constant kNotInUseErr -6720 Object not in use (e.g. cannot abort if not already in use).
- @constant kInUseErr -6721 Object is in use (e.g. cannot reuse active param blocks).
- @constant kTimeoutErr -6722 Timeout occurred.
- @constant kCanceledErr -6723 Operation canceled (successful cancel).
- @constant kAlreadyCanceledErr -6724 Operation has already been canceled.
- @constant kCannotCancelErr -6725 Operation could not be canceled (maybe already done or invalid).
- @constant kDeletedErr -6726 Object has already been deleted.
- @constant kNotFoundErr -6727 Something was not found.
- @constant kNoMemoryErr -6728 Not enough memory was available to perform the operation.
- @constant kNoResourcesErr -6729 Resources unavailable to perform the operation.
- @constant kDuplicateErr -6730 Duplicate found or something is a duplicate.
- @constant kImmutableErr -6731 Entity is not changeable.
- @constant kUnsupportedDataErr -6732 Data is unknown or not supported.
- @constant kIntegrityErr -6733 Data is corrupt.
- @constant kIncompatibleErr -6734 Data is not compatible or it is in an incompatible format.
- @constant kUnsupportedErr -6735 Feature or option is not supported.
- @constant kUnexpectedErr -6736 Error occurred that was not expected.
- @constant kValueErr -6737 Value is not appropriate.
- @constant kNotReadableErr -6738 Could not read or reading is not allowed.
- @constant kNotWritableErr -6739 Could not write or writing is not allowed.
- @constant kBadReferenceErr -6740 An invalid or inappropriate reference was specified.
- @constant kFlagErr -6741 An invalid, inappropriate, or unsupported flag was specified.
- @constant kMalformedErr -6742 Something was not formed correctly.
- @constant kSizeErr -6743 Size was too big, too small, or not appropriate.
- @constant kNameErr -6744 Name was not correct, allowed, or appropriate.
- @constant kNotReadyErr -6745 Device or service is not ready.
- @constant kReadErr -6746 Could not read.
- @constant kWriteErr -6747 Could not write.
- @constant kMismatchErr -6748 Something does not match.
- @constant kDateErr -6749 Date is invalid or out-of-range.
- @constant kUnderrunErr -6750 Less data than expected.
- @constant kOverrunErr -6751 More data than expected.
- @constant kEndingErr -6752 Connection, session, or something is ending.
- @constant kConnectionErr -6753 Connection failed or could not be established.
- @constant kAuthenticationErr -6754 Authentication failed or is not supported.
- @constant kOpenErr -6755 Could not open file, pipe, device, etc.
- @constant kTypeErr -6756 Incorrect or incompatible type (e.g. file, data, etc.).
- @constant kSkipErr -6757 Items should be or was skipped.
- @constant kNoAckErr -6758 No acknowledge.
- @constant kCollisionErr -6759 Collision occurred (e.g. two on bus at same time).
- @constant kBackoffErr -6760 Backoff in progress and operation intentionally failed.
- @constant kNoAddressAckErr -6761 No acknowledge of address.
- @constant kBusyErr -6762 Cannot perform because something is busy.
- @constant kNoSpaceErr -6763 Not enough space to perform operation.
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
- #if( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
- typedef int32_t OSStatus;
- #endif
-#endif
-
-#define kNoErr 0
-#define kInProgressErr 1
-
-// Generic error codes are in the range -6700 to -6779.
-
-#define kGenericErrorBase -6700 // Starting error code for all generic errors.
-
-#define kUnknownErr -6700
-#define kOptionErr -6701
-#define kSelectorErr -6702
-#define kExecutionStateErr -6703
-#define kPathErr -6704
-#define kParamErr -6705
-#define kParamCountErr -6706
-#define kCommandErr -6707
-#define kIDErr -6708
-#define kStateErr -6709
-#define kRangeErr -6710
-#define kRequestErr -6711
-#define kResponseErr -6712
-#define kChecksumErr -6713
-#define kNotHandledErr -6714
-#define kVersionErr -6715
-#define kSignatureErr -6716
-#define kFormatErr -6717
-#define kNotInitializedErr -6718
-#define kAlreadyInitializedErr -6719
-#define kNotInUseErr -6720
-#define kInUseErr -6721
-#define kTimeoutErr -6722
-#define kCanceledErr -6723
-#define kAlreadyCanceledErr -6724
-#define kCannotCancelErr -6725
-#define kDeletedErr -6726
-#define kNotFoundErr -6727
-#define kNoMemoryErr -6728
-#define kNoResourcesErr -6729
-#define kDuplicateErr -6730
-#define kImmutableErr -6731
-#define kUnsupportedDataErr -6732
-#define kIntegrityErr -6733
-#define kIncompatibleErr -6734
-#define kUnsupportedErr -6735
-#define kUnexpectedErr -6736
-#define kValueErr -6737
-#define kNotReadableErr -6738
-#define kNotWritableErr -6739
-#define kBadReferenceErr -6740
-#define kFlagErr -6741
-#define kMalformedErr -6742
-#define kSizeErr -6743
-#define kNameErr -6744
-#define kNotReadyErr -6745
-#define kReadErr -6746
-#define kWriteErr -6747
-#define kMismatchErr -6748
-#define kDateErr -6749
-#define kUnderrunErr -6750
-#define kOverrunErr -6751
-#define kEndingErr -6752
-#define kConnectionErr -6753
-#define kAuthenticationErr -6754
-#define kOpenErr -6755
-#define kTypeErr -6756
-#define kSkipErr -6757
-#define kNoAckErr -6758
-#define kCollisionErr -6759
-#define kBackoffErr -6760
-#define kNoAddressAckErr -6761
-#define kBusyErr -6762
-#define kNoSpaceErr -6763
-
-#define kGenericErrorEnd -6779 // Last generic error code (inclusive)
-
-#if 0
-#pragma mark == Mac Compatibility ==
-#endif
-
-//===========================================================================================================================
-// Mac Compatibility
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum Duration
-
- @abstract Type used to specify a duration of time.
-
- @constant kDurationImmediate Indicates no delay/wait time.
- @constant kDurationMicrosecond Microsecond units.
- @constant kDurationMillisecond Millisecond units.
- @constant kDurationSecond Second units.
- @constant kDurationMinute Minute units.
- @constant kDurationHour Hour units.
- @constant kDurationDay Day units.
- @constant kDurationForever Infinite period of time (no timeout).
-
- @discussion
-
- Duration values are intended to be multiplied by the specific interval to achieve an actual duration. For example,
- to wait for 5 seconds you would use "5 * kDurationSecond".
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
- #if( !TARGET_OS_MAC )
- typedef int32_t Duration;
- #endif
-#endif
-
-#define kDurationImmediate 0L
-#define kDurationMicrosecond -1L
-#define kDurationMillisecond 1L
-#define kDurationSecond ( 1000L * kDurationMillisecond )
-#define kDurationMinute ( 60L * kDurationSecond )
-#define kDurationHour ( 60L * kDurationMinute )
-#define kDurationDay ( 24L * kDurationHour )
-#define kDurationForever 0x7FFFFFFFL
-
-// Seconds <-> Minutes <-> Hours <-> Days <-> Weeks <-> Months <-> Years conversions
-
-#define kNanosecondsPerMicrosecond 1000
-#define kNanosecondsPerMillisecond 1000000
-#define kNanosecondsPerSecond 1000000000
-#define kMicrosecondsPerSecond 1000000
-#define kMicrosecondsPerMillisecond 1000
-#define kMillisecondsPerSecond 1000
-#define kSecondsPerMinute 60
-#define kSecondsPerHour ( 60 * 60 ) // 3600
-#define kSecondsPerDay ( 60 * 60 * 24 ) // 86400
-#define kSecondsPerWeek ( 60 * 60 * 24 * 7 ) // 604800
-#define kMinutesPerHour 60
-#define kMinutesPerDay ( 60 * 24 ) // 1440
-#define kHoursPerDay 24
-#define kDaysPerWeek 7
-#define kWeeksPerYear 52
-#define kMonthsPerYear 12
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined VersionStages
-
- @abstract NumVersion-style version stages.
-*/
-
-#define kVersionStageDevelopment 0x20
-#define kVersionStageAlpha 0x40
-#define kVersionStageBeta 0x60
-#define kVersionStageFinal 0x80
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function NumVersionBuild
-
- @abstract Builds a 32-bit Mac-style NumVersion value (e.g. NumVersionBuild( 1, 2, 3, kVersionStageBeta, 4 ) -> 1.2.3b4).
-*/
-
-#define NumVersionBuild( MAJOR, MINOR, BUGFIX, STAGE, REV ) \
- ( ( ( ( MAJOR ) & 0xFF ) << 24 ) | \
- ( ( ( MINOR ) & 0x0F ) << 20 ) | \
- ( ( ( BUGFIX ) & 0x0F ) << 16 ) | \
- ( ( ( STAGE ) & 0xFF ) << 8 ) | \
- ( ( ( REV ) & 0xFF ) ) )
-
-#define NumVersionExtractMajor( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 24 ) & 0xFF ) )
-#define NumVersionExtractMinorAndBugFix( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0xFF ) )
-#define NumVersionExtractMinor( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 20 ) & 0x0F ) )
-#define NumVersionExtractBugFix( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0x0F ) )
-#define NumVersionExtractStage( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 8 ) & 0xFF ) )
-#define NumVersionExtractRevision( VERSION ) ( (uint8_t)( ( VERSION ) & 0xFF ) )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function NumVersionCompare
-
- @abstract Compares two NumVersion values and returns the following values:
-
- left < right -> -1
- left > right -> 1
- left = right -> 0
-*/
-
-#if( TARGET_LANGUAGE_C_LIKE )
- int NumVersionCompare( uint32_t inLeft, uint32_t inRight );
-#endif
-
-#if 0
-#pragma mark == Binary Constants ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined binary_4
-
- @abstract Macro to generate an 4-bit constant using binary notation (e.g. binary_4( 1010 ) == 0xA).
-*/
-
-#define binary_4( a ) binary_4_hex_wrap( hex_digit4( a ) )
-#define binary_4_hex_wrap( a ) binary_4_hex( a )
-#define binary_4_hex( a ) ( 0x ## a )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined binary_8
-
- @abstract Macro to generate an 8-bit constant using binary notation (e.g. binary_8( 01111011 ) == 0x7B).
-*/
-
-#define binary_8( a ) binary_8_hex_wrap( hex_digit8( a ) )
-#define binary_8_hex_wrap( a ) binary_8_hex( a )
-#define binary_8_hex( a ) ( 0x ## a )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined binary_16
-
- @abstract Macro to generate an 16-bit constant using binary notation (e.g. binary_16( 01111011, 01111011 ) == 0x7B7B).
-*/
-
-#define binary_16( a, b ) binary_16_hex_wrap( hex_digit8( a ), hex_digit8( b ) )
-#define binary_16_hex_wrap( a, b ) binary_16_hex( a, b )
-#define binary_16_hex( a, b ) ( 0x ## a ## b )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined binary_32
-
- @abstract Macro to generate an 32-bit constant using binary notation
- (e.g. binary_32( 01111011, 01111011, 01111011, 01111011 ) == 0x7B7B7B7B).
-*/
-
-#define binary_32( a, b, c, d ) binary_32_hex_wrap( hex_digit8( a ), hex_digit8( b ), hex_digit8( c ), hex_digit8( d ) )
-#define binary_32_hex_wrap( a, b, c, d ) binary_32_hex( a, b, c, d )
-#define binary_32_hex( a, b, c, d ) ( 0x ## a ## b ## c ## d )
-
-// Binary Constant Helpers
-
-#define hex_digit8( a ) HEX_DIGIT_ ## a
-#define hex_digit4( a ) HEX_DIGIT_ ## 0000 ## a
-
-#define HEX_DIGIT_00000000 00
-#define HEX_DIGIT_00000001 01
-#define HEX_DIGIT_00000010 02
-#define HEX_DIGIT_00000011 03
-#define HEX_DIGIT_00000100 04
-#define HEX_DIGIT_00000101 05
-#define HEX_DIGIT_00000110 06
-#define HEX_DIGIT_00000111 07
-#define HEX_DIGIT_00001000 08
-#define HEX_DIGIT_00001001 09
-#define HEX_DIGIT_00001010 0A
-#define HEX_DIGIT_00001011 0B
-#define HEX_DIGIT_00001100 0C
-#define HEX_DIGIT_00001101 0D
-#define HEX_DIGIT_00001110 0E
-#define HEX_DIGIT_00001111 0F
-#define HEX_DIGIT_00010000 10
-#define HEX_DIGIT_00010001 11
-#define HEX_DIGIT_00010010 12
-#define HEX_DIGIT_00010011 13
-#define HEX_DIGIT_00010100 14
-#define HEX_DIGIT_00010101 15
-#define HEX_DIGIT_00010110 16
-#define HEX_DIGIT_00010111 17
-#define HEX_DIGIT_00011000 18
-#define HEX_DIGIT_00011001 19
-#define HEX_DIGIT_00011010 1A
-#define HEX_DIGIT_00011011 1B
-#define HEX_DIGIT_00011100 1C
-#define HEX_DIGIT_00011101 1D
-#define HEX_DIGIT_00011110 1E
-#define HEX_DIGIT_00011111 1F
-#define HEX_DIGIT_00100000 20
-#define HEX_DIGIT_00100001 21
-#define HEX_DIGIT_00100010 22
-#define HEX_DIGIT_00100011 23
-#define HEX_DIGIT_00100100 24
-#define HEX_DIGIT_00100101 25
-#define HEX_DIGIT_00100110 26
-#define HEX_DIGIT_00100111 27
-#define HEX_DIGIT_00101000 28
-#define HEX_DIGIT_00101001 29
-#define HEX_DIGIT_00101010 2A
-#define HEX_DIGIT_00101011 2B
-#define HEX_DIGIT_00101100 2C
-#define HEX_DIGIT_00101101 2D
-#define HEX_DIGIT_00101110 2E
-#define HEX_DIGIT_00101111 2F
-#define HEX_DIGIT_00110000 30
-#define HEX_DIGIT_00110001 31
-#define HEX_DIGIT_00110010 32
-#define HEX_DIGIT_00110011 33
-#define HEX_DIGIT_00110100 34
-#define HEX_DIGIT_00110101 35
-#define HEX_DIGIT_00110110 36
-#define HEX_DIGIT_00110111 37
-#define HEX_DIGIT_00111000 38
-#define HEX_DIGIT_00111001 39
-#define HEX_DIGIT_00111010 3A
-#define HEX_DIGIT_00111011 3B
-#define HEX_DIGIT_00111100 3C
-#define HEX_DIGIT_00111101 3D
-#define HEX_DIGIT_00111110 3E
-#define HEX_DIGIT_00111111 3F
-#define HEX_DIGIT_01000000 40
-#define HEX_DIGIT_01000001 41
-#define HEX_DIGIT_01000010 42
-#define HEX_DIGIT_01000011 43
-#define HEX_DIGIT_01000100 44
-#define HEX_DIGIT_01000101 45
-#define HEX_DIGIT_01000110 46
-#define HEX_DIGIT_01000111 47
-#define HEX_DIGIT_01001000 48
-#define HEX_DIGIT_01001001 49
-#define HEX_DIGIT_01001010 4A
-#define HEX_DIGIT_01001011 4B
-#define HEX_DIGIT_01001100 4C
-#define HEX_DIGIT_01001101 4D
-#define HEX_DIGIT_01001110 4E
-#define HEX_DIGIT_01001111 4F
-#define HEX_DIGIT_01010000 50
-#define HEX_DIGIT_01010001 51
-#define HEX_DIGIT_01010010 52
-#define HEX_DIGIT_01010011 53
-#define HEX_DIGIT_01010100 54
-#define HEX_DIGIT_01010101 55
-#define HEX_DIGIT_01010110 56
-#define HEX_DIGIT_01010111 57
-#define HEX_DIGIT_01011000 58
-#define HEX_DIGIT_01011001 59
-#define HEX_DIGIT_01011010 5A
-#define HEX_DIGIT_01011011 5B
-#define HEX_DIGIT_01011100 5C
-#define HEX_DIGIT_01011101 5D
-#define HEX_DIGIT_01011110 5E
-#define HEX_DIGIT_01011111 5F
-#define HEX_DIGIT_01100000 60
-#define HEX_DIGIT_01100001 61
-#define HEX_DIGIT_01100010 62
-#define HEX_DIGIT_01100011 63
-#define HEX_DIGIT_01100100 64
-#define HEX_DIGIT_01100101 65
-#define HEX_DIGIT_01100110 66
-#define HEX_DIGIT_01100111 67
-#define HEX_DIGIT_01101000 68
-#define HEX_DIGIT_01101001 69
-#define HEX_DIGIT_01101010 6A
-#define HEX_DIGIT_01101011 6B
-#define HEX_DIGIT_01101100 6C
-#define HEX_DIGIT_01101101 6D
-#define HEX_DIGIT_01101110 6E
-#define HEX_DIGIT_01101111 6F
-#define HEX_DIGIT_01110000 70
-#define HEX_DIGIT_01110001 71
-#define HEX_DIGIT_01110010 72
-#define HEX_DIGIT_01110011 73
-#define HEX_DIGIT_01110100 74
-#define HEX_DIGIT_01110101 75
-#define HEX_DIGIT_01110110 76
-#define HEX_DIGIT_01110111 77
-#define HEX_DIGIT_01111000 78
-#define HEX_DIGIT_01111001 79
-#define HEX_DIGIT_01111010 7A
-#define HEX_DIGIT_01111011 7B
-#define HEX_DIGIT_01111100 7C
-#define HEX_DIGIT_01111101 7D
-#define HEX_DIGIT_01111110 7E
-#define HEX_DIGIT_01111111 7F
-#define HEX_DIGIT_10000000 80
-#define HEX_DIGIT_10000001 81
-#define HEX_DIGIT_10000010 82
-#define HEX_DIGIT_10000011 83
-#define HEX_DIGIT_10000100 84
-#define HEX_DIGIT_10000101 85
-#define HEX_DIGIT_10000110 86
-#define HEX_DIGIT_10000111 87
-#define HEX_DIGIT_10001000 88
-#define HEX_DIGIT_10001001 89
-#define HEX_DIGIT_10001010 8A
-#define HEX_DIGIT_10001011 8B
-#define HEX_DIGIT_10001100 8C
-#define HEX_DIGIT_10001101 8D
-#define HEX_DIGIT_10001110 8E
-#define HEX_DIGIT_10001111 8F
-#define HEX_DIGIT_10010000 90
-#define HEX_DIGIT_10010001 91
-#define HEX_DIGIT_10010010 92
-#define HEX_DIGIT_10010011 93
-#define HEX_DIGIT_10010100 94
-#define HEX_DIGIT_10010101 95
-#define HEX_DIGIT_10010110 96
-#define HEX_DIGIT_10010111 97
-#define HEX_DIGIT_10011000 98
-#define HEX_DIGIT_10011001 99
-#define HEX_DIGIT_10011010 9A
-#define HEX_DIGIT_10011011 9B
-#define HEX_DIGIT_10011100 9C
-#define HEX_DIGIT_10011101 9D
-#define HEX_DIGIT_10011110 9E
-#define HEX_DIGIT_10011111 9F
-#define HEX_DIGIT_10100000 A0
-#define HEX_DIGIT_10100001 A1
-#define HEX_DIGIT_10100010 A2
-#define HEX_DIGIT_10100011 A3
-#define HEX_DIGIT_10100100 A4
-#define HEX_DIGIT_10100101 A5
-#define HEX_DIGIT_10100110 A6
-#define HEX_DIGIT_10100111 A7
-#define HEX_DIGIT_10101000 A8
-#define HEX_DIGIT_10101001 A9
-#define HEX_DIGIT_10101010 AA
-#define HEX_DIGIT_10101011 AB
-#define HEX_DIGIT_10101100 AC
-#define HEX_DIGIT_10101101 AD
-#define HEX_DIGIT_10101110 AE
-#define HEX_DIGIT_10101111 AF
-#define HEX_DIGIT_10110000 B0
-#define HEX_DIGIT_10110001 B1
-#define HEX_DIGIT_10110010 B2
-#define HEX_DIGIT_10110011 B3
-#define HEX_DIGIT_10110100 B4
-#define HEX_DIGIT_10110101 B5
-#define HEX_DIGIT_10110110 B6
-#define HEX_DIGIT_10110111 B7
-#define HEX_DIGIT_10111000 B8
-#define HEX_DIGIT_10111001 B9
-#define HEX_DIGIT_10111010 BA
-#define HEX_DIGIT_10111011 BB
-#define HEX_DIGIT_10111100 BC
-#define HEX_DIGIT_10111101 BD
-#define HEX_DIGIT_10111110 BE
-#define HEX_DIGIT_10111111 BF
-#define HEX_DIGIT_11000000 C0
-#define HEX_DIGIT_11000001 C1
-#define HEX_DIGIT_11000010 C2
-#define HEX_DIGIT_11000011 C3
-#define HEX_DIGIT_11000100 C4
-#define HEX_DIGIT_11000101 C5
-#define HEX_DIGIT_11000110 C6
-#define HEX_DIGIT_11000111 C7
-#define HEX_DIGIT_11001000 C8
-#define HEX_DIGIT_11001001 C9
-#define HEX_DIGIT_11001010 CA
-#define HEX_DIGIT_11001011 CB
-#define HEX_DIGIT_11001100 CC
-#define HEX_DIGIT_11001101 CD
-#define HEX_DIGIT_11001110 CE
-#define HEX_DIGIT_11001111 CF
-#define HEX_DIGIT_11010000 D0
-#define HEX_DIGIT_11010001 D1
-#define HEX_DIGIT_11010010 D2
-#define HEX_DIGIT_11010011 D3
-#define HEX_DIGIT_11010100 D4
-#define HEX_DIGIT_11010101 D5
-#define HEX_DIGIT_11010110 D6
-#define HEX_DIGIT_11010111 D7
-#define HEX_DIGIT_11011000 D8
-#define HEX_DIGIT_11011001 D9
-#define HEX_DIGIT_11011010 DA
-#define HEX_DIGIT_11011011 DB
-#define HEX_DIGIT_11011100 DC
-#define HEX_DIGIT_11011101 DD
-#define HEX_DIGIT_11011110 DE
-#define HEX_DIGIT_11011111 DF
-#define HEX_DIGIT_11100000 E0
-#define HEX_DIGIT_11100001 E1
-#define HEX_DIGIT_11100010 E2
-#define HEX_DIGIT_11100011 E3
-#define HEX_DIGIT_11100100 E4
-#define HEX_DIGIT_11100101 E5
-#define HEX_DIGIT_11100110 E6
-#define HEX_DIGIT_11100111 E7
-#define HEX_DIGIT_11101000 E8
-#define HEX_DIGIT_11101001 E9
-#define HEX_DIGIT_11101010 EA
-#define HEX_DIGIT_11101011 EB
-#define HEX_DIGIT_11101100 EC
-#define HEX_DIGIT_11101101 ED
-#define HEX_DIGIT_11101110 EE
-#define HEX_DIGIT_11101111 EF
-#define HEX_DIGIT_11110000 F0
-#define HEX_DIGIT_11110001 F1
-#define HEX_DIGIT_11110010 F2
-#define HEX_DIGIT_11110011 F3
-#define HEX_DIGIT_11110100 F4
-#define HEX_DIGIT_11110101 F5
-#define HEX_DIGIT_11110110 F6
-#define HEX_DIGIT_11110111 F7
-#define HEX_DIGIT_11111000 F8
-#define HEX_DIGIT_11111001 F9
-#define HEX_DIGIT_11111010 FA
-#define HEX_DIGIT_11111011 FB
-#define HEX_DIGIT_11111100 FC
-#define HEX_DIGIT_11111101 FD
-#define HEX_DIGIT_11111110 FE
-#define HEX_DIGIT_11111111 FF
-
-#if 0
-#pragma mark == Debugging ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function CommonServicesTest
-
- @abstract Unit test.
-*/
-
-#if( DEBUG )
- #if( TARGET_LANGUAGE_C_LIKE )
- OSStatus CommonServicesTest( void );
- #endif
-#endif
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif // __COMMON_SERVICES__
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ConfigDialog.cpp,v $
+Revision 1.3 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/03/03 19:55:21 shersche
<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ConfigDialog.h,v $
+Revision 1.3 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/03/03 19:55:21 shersche
<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ConfigPropertySheet.cpp,v $
+Revision 1.5 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.4 2005/10/05 20:46:50 herscher
<rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ConfigPropertySheet.h,v $
+Revision 1.5 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.4 2005/03/03 19:55:21 shersche
<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
DECLARE_MESSAGE_MAP()
afx_msg BOOL OnInitDialog();
- afx_msg BOOL OnCommand( WPARAM wParam, LPARAM lParam );\r
- afx_msg LONG OnDataReady( WPARAM inWParam, LPARAM inLParam );\r
- afx_msg LONG OnRegistryChanged( WPARAM inWParam, LPARAM inLParam );\r
+ afx_msg BOOL OnCommand( WPARAM wParam, LPARAM lParam );
+
+ afx_msg LONG OnDataReady( WPARAM inWParam, LPARAM inLParam );
+
+ afx_msg LONG OnRegistryChanged( WPARAM inWParam, LPARAM inLParam );
+
void OnEndDialog();
private:
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ControlPanel.cpp,v $
+Revision 1.4 2007/04/27 20:42:11 herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+Revision 1.3 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/03/03 19:55:22 shersche
<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
CCPApplet::OnRun(CWnd* pParentWnd)
{
LRESULT lResult = 1;
- CWnd * pWnd = (CWnd*) m_uiClass->CreateObject();
+ CWnd * pWnd;
+
+ InitCommonControls();
+
+ pWnd = (CWnd*) m_uiClass->CreateObject();
if ( pWnd )
{
+; -*- tab-width: 4 -*-
;
; Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
;
-; @APPLE_LICENSE_HEADER_START@
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
;
-; This file contains Original Code and/or Modifications of Original Code
-; as defined in and that are subject to the Apple Public Source License
-; Version 2.0 (the 'License'). You may not use this file except in
-; compliance with the License. Please obtain a copy of the License at
-; http://www.opensource.apple.com/apsl/ and read it before using this
-; file.
+; http://www.apache.org/licenses/LICENSE-2.0
;
-; The Original Code and all software distributed under the License are
-; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-; Please see the License for the specific language governing rights and
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
; limitations under the License.
-;
-; @APPLE_LICENSE_HEADER_END@
;
; Change History (most recent first):
;
; $Log: ControlPanel.def,v $
+; Revision 1.4 2006/08/14 23:25:28 cheshire
+; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+;
; Revision 1.3 2005/03/03 19:55:22 shersche
; <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
;
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ControlPanel.h,v $
+Revision 1.3 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/03/03 19:55:21 shersche
<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
#pragma code_page(1252)
#endif //_WIN32
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", "Apple Computer, Inc."
- VALUE "FileDescription", "Bonjour Configuration Applet"
- VALUE "FileVersion", MASTER_PROD_VERS_STR
- VALUE "InternalName", "Bonjour.cpl"
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
- VALUE "OriginalFilename", "Bonjour.cpl"
- VALUE "ProductName", MASTER_PROD_NAME
- VALUE "ProductVersion", MASTER_PROD_VERS_STR
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
RelativePath="res\controlpanel.ico">\r
</File>\r
<File\r
- RelativePath="ControlPanel.rc">\r
+ RelativePath="ControlPanelDll.rc">\r
</File>\r
<File\r
- RelativePath="res\ControlPanel.rc2">\r
+ RelativePath="res\ControlPanelDll.rc2">\r
</File>\r
<File\r
RelativePath="res\failure.ico">\r
--- /dev/null
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+ BLOCK "StringFileInfo"\r
+ BEGIN\r
+ BLOCK "040904e4"\r
+ BEGIN\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
+ VALUE "FileDescription", "Bonjour Configuration Applet"\r
+ VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+ VALUE "InternalName", "Bonjour.cpl"\r
+ VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+ VALUE "OriginalFilename", "Bonjour.cpl"\r
+ VALUE "ProductName", MASTER_PROD_NAME\r
+ VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+ END\r
+ END\r
+ BLOCK "VarFileInfo"\r
+ BEGIN\r
+ VALUE "Translation", 0x409, 1252\r
+ END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// RT_MANIFEST\r
+//\r
+\r
+2 RT_MANIFEST "res\\ControlPanel.dll.manifest"\r
+\r
+\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+ "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+ "#include ""afxres.h""\r\n"\r
+ "#include ""WinVersRes.h""\r\n"\r
+ "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+ "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+ "\r\n"\r
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+ "LANGUAGE 9, 1\r\n"\r
+ "#pragma code_page(1252)\r\n"\r
+ "#include ""afxres.rc"" // Standard components\r\n"\r
+ "#include ""ControlPanel.rc""\r\n"\r
+ "#endif\r\n"\r
+ "\0"\r
+END\r
+\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+#endif // English (U.S.) resources\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc" // Standard components\r
+#include "ControlPanel.rc"\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif // not APSTUDIO_INVOKED\r
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: ControlPanelExe.cpp,v $
+Revision 1.3 2007/04/27 21:43:00 herscher
+Update license info to Apache License, Version 2.0
+
+Revision 1.2 2007/04/27 20:42:12 herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+Revision 1.1.2.1 2007/04/27 18:13:55 herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+
+
+*/
+
+
+#include "ControlPanelExe.h"
+#include "ConfigDialog.h"
+#include "ConfigPropertySheet.h"
+#include "resource.h"
+
+#include <DebugServices.h>
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+// Static Declarations
+//---------------------------------------------------------------------------------------------------------------------------
+DEFINE_GUID(CLSID_ControlPanel, \r
+0x1207552c, 0xe59, 0x4d9f, 0x85, 0x54, 0xf1, 0xf8, 0x6, 0xcd, 0x7f, 0xa9);\r
+\r
+static LPCTSTR g_controlPanelGUID = TEXT( "{1207552C-0E59-4d9f-8554-F1F806CD7FA9}" );
+static LPCTSTR g_controlPanelName = TEXT( "Bonjour Control Panel" );
+static LPCTSTR g_controlPanelCategory = TEXT( "3,8" );
+static LPCTSTR g_controlPanelLocalizedName = g_controlPanelName;
+static LPCTSTR g_controlPanelInfoTip = TEXT( "Configures Wide-Area Bonjour" );
+
+static CCPApp theApp;
+
+//===========================================================================================================================
+// MyRegDeleteKey
+//===========================================================================================================================
+
+DEBUG_LOCAL OSStatus MyRegDeleteKey( HKEY hKeyRoot, LPTSTR lpSubKey )
+{
+ LPTSTR lpEnd;
+ OSStatus err;
+ DWORD dwSize;
+ TCHAR szName[MAX_PATH];
+ HKEY hKey;
+ FILETIME ftWrite;
+
+ // First, see if we can delete the key without having to recurse.
+
+ err = RegDeleteKey( hKeyRoot, lpSubKey );
+
+ if ( !err )
+ {
+ goto exit;
+ }
+
+ err = RegOpenKeyEx( hKeyRoot, lpSubKey, 0, KEY_READ, &hKey );
+ require_noerr( err, exit );
+
+ // Check for an ending slash and add one if it is missing.
+
+ lpEnd = lpSubKey + lstrlen(lpSubKey);
+
+ if ( *( lpEnd - 1 ) != TEXT( '\\' ) )
+ {
+ *lpEnd = TEXT('\\');
+ lpEnd++;
+ *lpEnd = TEXT('\0');
+ }
+
+ // Enumerate the keys
+
+ dwSize = MAX_PATH;
+ err = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
+
+ if ( !err )
+ {
+ do
+ {
+ lstrcpy (lpEnd, szName);
+
+ if ( !MyRegDeleteKey( hKeyRoot, lpSubKey ) )
+ {
+ break;
+ }
+
+ dwSize = MAX_PATH;
+
+ err = RegEnumKeyEx( hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite );
+
+ }
+ while ( !err );
+ }
+
+ lpEnd--;
+ *lpEnd = TEXT('\0');
+
+ RegCloseKey( hKey );
+
+ // Try again to delete the key.
+
+ err = RegDeleteKey(hKeyRoot, lpSubKey);
+ require_noerr( err, exit );
+
+exit:
+
+ return err;
+}
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+// CCPApp::CCPApp
+//---------------------------------------------------------------------------------------------------------------------------
+IMPLEMENT_DYNAMIC(CCPApp, CWinApp);
+
+CCPApp::CCPApp()
+{
+ debug_initialize( kDebugOutputTypeWindowsEventLog, "DNS-SD Control Panel", GetModuleHandle( NULL ) );
+ debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+// CCPApp::~CCPApp
+//---------------------------------------------------------------------------------------------------------------------------
+
+CCPApp::~CCPApp()
+{
+}
+
+
+void
+CCPApp::Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath )
+{
+ typedef struct RegistryBuilder RegistryBuilder;
+
+ struct RegistryBuilder
+ {
+ HKEY rootKey;
+ LPCTSTR subKey;
+ LPCTSTR valueName;
+ DWORD valueType;
+ LPCTSTR data;
+ };
+
+ OSStatus err;
+ size_t n;
+ size_t i;
+ HKEY key;
+ TCHAR keyName[ MAX_PATH ];
+ RegistryBuilder entries[] =
+ {
+ { HKEY_LOCAL_MACHINE, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s" ), NULL, REG_SZ, inName },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), NULL, NULL, NULL },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), TEXT( "System.ApplicationName" ), REG_SZ, inName },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), TEXT( "System.ControlPanel.Category" ), REG_SZ, inCategory },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), TEXT( "LocalizedString" ), REG_SZ, inLocalizedName },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), TEXT( "InfoTip" ), REG_SZ, inInfoTip },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\DefaultIcon" ), NULL, REG_SZ, inIconPath },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\Shell" ), NULL, NULL, NULL },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\Shell\\Open" ), NULL, NULL, NULL },
+ { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\Shell\\Open\\Command" ), NULL, REG_SZ, inExePath }
+ };
+ DWORD size;
+
+ // Register the registry entries.
+
+ n = sizeof_array( entries );
+ for( i = 0; i < n; ++i )
+ {
+ wsprintf( keyName, entries[ i ].subKey, inClsidString );
+ err = RegCreateKeyEx( entries[ i ].rootKey, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
+ require_noerr( err, exit );
+
+ if ( entries[ i ].data )
+ {
+ size = (DWORD)( ( lstrlen( entries[ i ].data ) + 1 ) * sizeof( TCHAR ) );
+ err = RegSetValueEx( key, entries[ i ].valueName, 0, entries[ i ].valueType, (LPBYTE) entries[ i ].data, size );
+ require_noerr( err, exit );
+ }
+
+ RegCloseKey( key );
+ }
+
+exit:
+ return;
+}
+
+
+//-----------------------------------------------------------
+// CCPApp::Unregister
+//-----------------------------------------------------------
+void
+CCPApp::Unregister( LPCTSTR clsidString )
+{
+ TCHAR keyName[ MAX_PATH * 2 ];
+
+ wsprintf( keyName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s", clsidString );
+ MyRegDeleteKey( HKEY_LOCAL_MACHINE, keyName );
+
+ wsprintf( keyName, L"CLSID\\%s", clsidString );
+ MyRegDeleteKey( HKEY_CLASSES_ROOT, keyName );
+}
+
+
+
+//-----------------------------------------------------------
+// CCPApp::InitInstance
+//-----------------------------------------------------------
+
+BOOL
+CCPApp::InitInstance()
+{
+ CCommandLineInfo commandLine;
+ OSStatus err = kNoErr;
+
+ // InitCommonControls() is required on Windows XP if an application
+ // manifest specifies use of ComCtl32.dll version 6 or later to enable
+ // visual styles. Otherwise, any window creation will fail.
+
+ InitCommonControls();
+
+ CWinApp::InitInstance();
+
+ AfxEnableControlContainer();
+
+ ParseCommandLine( commandLine );
+
+ if ( commandLine.m_nShellCommand == CCommandLineInfo::AppRegister )
+ {
+ TCHAR iconPath[ MAX_PATH + 12 ] = TEXT( "" );
+ TCHAR exePath[ MAX_PATH ] = TEXT( "" );
+ DWORD nChars;
+ OSStatus err;
+
+ nChars = GetModuleFileName( NULL, exePath, sizeof_array( exePath ) );\r
+ err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );\r
+ require_noerr( err, exit );
+
+ wsprintf( iconPath, L"%s,-%d", exePath, IDR_APPLET );
+
+ Register( g_controlPanelGUID, g_controlPanelName, g_controlPanelCategory, g_controlPanelName, g_controlPanelInfoTip, iconPath, exePath );
+ }
+ else if ( commandLine.m_nShellCommand == CCommandLineInfo::AppUnregister )
+ {
+ Unregister( g_controlPanelGUID );
+ }
+ else
+ {
+ CString name;
+ CConfigPropertySheet dlg;
+
+ name.LoadString( IDR_APPLET );
+ dlg.Construct( name, NULL, 0 );
+
+ m_pMainWnd = &dlg;
+
+ try
+ {
+ INT_PTR nResponse = dlg.DoModal();
+
+ if (nResponse == IDOK)
+ {
+ // TODO: Place code here to handle when the dialog is
+ // dismissed with OK
+ }
+ else if (nResponse == IDCANCEL)
+ {
+ // TODO: Place code here to handle when the dialog is
+ // dismissed with Cancel
+ }
+ }
+ catch (...)
+ {
+ MessageBox(NULL, L"", L"", MB_OK|MB_ICONEXCLAMATION);
+ }
+ }
+
+ if ( err )
+ {
+ MessageBox( NULL, L"", L"", MB_ICONERROR | MB_OK );
+ }
+
+exit:
+
+ // Since the dialog has been closed, return FALSE so that we exit the
+ // application, rather than start the application's message pump.
+ return FALSE;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ Change History (most recent first):
+
+$Log: ControlPanelExe.h,v $
+Revision 1.3 2007/04/27 21:43:00 herscher
+Update license info to Apache License, Version 2.0
+
+Revision 1.2 2007/04/27 20:42:12 herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+Revision 1.1.2.1 2007/04/27 18:13:55 herscher
+<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
+
+
+*/
+
+
+#pragma once
+
+#include "stdafx.h"
+
+
+//-------------------------------------------------
+// CCPApp
+//-------------------------------------------------
+
+class CCPApp : public CWinApp
+{
+public:
+
+ CCPApp();
+ virtual ~CCPApp();
+
+protected:
+
+ virtual BOOL InitInstance();
+
+ void
+ Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath );
+
+ void
+ Unregister( LPCTSTR clsidString );
+
+ DECLARE_DYNAMIC(CCPApp);
+};
--- /dev/null
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+ BLOCK "StringFileInfo"\r
+ BEGIN\r
+ BLOCK "040904e4"\r
+ BEGIN\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
+ VALUE "FileDescription", "Bonjour Configuration Applet"\r
+ VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+ VALUE "InternalName", "ControlPanel.exe"\r
+ VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+ VALUE "OriginalFilename", "ControlPanel.exe"\r
+ VALUE "ProductName", MASTER_PROD_NAME\r
+ VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+ END\r
+ END\r
+ BLOCK "VarFileInfo"\r
+ BEGIN\r
+ VALUE "Translation", 0x409, 1252\r
+ END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// RT_MANIFEST\r
+//\r
+\r
+1 RT_MANIFEST "res\\ControlPanel.exe.manifest"\r
+\r
+\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+ "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+ "#include ""afxres.h""\r\n"\r
+ "#include ""WinVersRes.h""\r\n"\r
+ "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+ "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+ "\r\n"\r
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+ "LANGUAGE 9, 1\r\n"\r
+ "#pragma code_page(1252)\r\n"\r
+ "#include ""afxres.rc"" // Standard components\r\n"\r
+ "#include ""ControlPanel.rc""\r\n"\r
+ "#endif\r\n"\r
+ "\0"\r
+END\r
+\r
+#endif // APSTUDIO_INVOKED\r
+\r
+\r
+#endif // English (U.S.) resources\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc" // Standard components\r
+#include "ControlPanel.rc"\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif // not APSTUDIO_INVOKED\r
--- /dev/null
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+ ProjectType="Visual C++"\r
+ Version="7.10"\r
+ Name="ControlPanel (Vista)"\r
+ ProjectGUID="{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
+ SccProjectName=""\r
+ SccLocalPath=""\r
+ Keyword="MFCProj">\r
+ <Platforms>\r
+ <Platform\r
+ Name="Win32"/>\r
+ </Platforms>\r
+ <Configurations>\r
+ <Configuration\r
+ Name="Debug|Win32"\r
+ OutputDirectory=".\Debug"\r
+ IntermediateDirectory=".\Debug"\r
+ ConfigurationType="1"\r
+ UseOfMFC="1"\r
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
+ PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501"\r
+ StringPooling="TRUE"\r
+ MinimalRebuild="TRUE"\r
+ BasicRuntimeChecks="3"\r
+ RuntimeLibrary="1"\r
+ UsePrecompiledHeader="0"\r
+ PrecompiledHeaderThrough=""\r
+ PrecompiledHeaderFile=""\r
+ AssemblerListingLocation=".\Debug/"\r
+ ObjectFile=".\Debug/"\r
+ ProgramDataBaseFileName=".\Debug/"\r
+ WarningLevel="4"\r
+ SuppressStartupBanner="TRUE"\r
+ Detect64BitPortabilityProblems="TRUE"\r
+ DebugInformationFormat="4"\r
+ CallingConvention="0"\r
+ DisableSpecificWarnings="4311;4312"/>\r
+ <Tool\r
+ Name="VCCustomBuildTool"/>\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ AdditionalDependencies="../DLL/Debug/dnssd.lib ws2_32.lib"\r
+ OutputFile="Debug/ControlPanel.exe"\r
+ LinkIncremental="2"\r
+ SuppressStartupBanner="TRUE"\r
+ GenerateDebugInformation="TRUE"\r
+ ProgramDatabaseFile=".\Debug/ControlPanel.pdb"\r
+ SubSystem="2"\r
+ EntryPointSymbol="wWinMainCRTStartup"\r
+ TargetMachine="1"/>\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ PreprocessorDefinitions="_DEBUG"\r
+ MkTypLibCompatible="FALSE"/>\r
+ <Tool\r
+ Name="VCPostBuildEventTool"/>\r
+ <Tool\r
+ Name="VCPreBuildEventTool"/>\r
+ <Tool\r
+ Name="VCPreLinkEventTool"/>\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ PreprocessorDefinitions="_DEBUG"\r
+ Culture="1033"\r
+ AdditionalIncludeDirectories="../"/>\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"/>\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"/>\r
+ <Tool\r
+ Name="VCWebDeploymentTool"/>\r
+ <Tool\r
+ Name="VCManagedWrapperGeneratorTool"/>\r
+ <Tool\r
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+ </Configuration>\r
+ <Configuration\r
+ Name="Release|Win32"\r
+ OutputDirectory=".\Release"\r
+ IntermediateDirectory=".\Release"\r
+ ConfigurationType="1"\r
+ UseOfMFC="1"\r
+ CharacterSet="2">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="2"\r
+ InlineFunctionExpansion="1"\r
+ AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE"\r
+ StringPooling="TRUE"\r
+ MinimalRebuild="FALSE"\r
+ RuntimeLibrary="0"\r
+ EnableFunctionLevelLinking="TRUE"\r
+ TreatWChar_tAsBuiltInType="TRUE"\r
+ UsePrecompiledHeader="0"\r
+ ObjectFile=".\Release/"\r
+ ProgramDataBaseFileName=".\Release/"\r
+ WarningLevel="4"\r
+ SuppressStartupBanner="TRUE"\r
+ DisableSpecificWarnings="4702"/>\r
+ <Tool\r
+ Name="VCCustomBuildTool"/>\r
+ <Tool\r
+ Name="VCLinkerTool"\r
+ AdditionalDependencies="../DLL/Release/dnssd.lib ws2_32.lib"\r
+ OutputFile="Release/ControlPanel.exe"\r
+ LinkIncremental="1"\r
+ SuppressStartupBanner="TRUE"\r
+ ProgramDatabaseFile=".\Release/ControlPanel.pdb"\r
+ SubSystem="2"\r
+ OptimizeReferences="0"\r
+ EnableCOMDATFolding="0"\r
+ EntryPointSymbol="wWinMainCRTStartup"\r
+ TargetMachine="1"/>\r
+ <Tool\r
+ Name="VCMIDLTool"\r
+ PreprocessorDefinitions="NDEBUG"\r
+ MkTypLibCompatible="FALSE"/>\r
+ <Tool\r
+ Name="VCPostBuildEventTool"/>\r
+ <Tool\r
+ Name="VCPreBuildEventTool"/>\r
+ <Tool\r
+ Name="VCPreLinkEventTool"/>\r
+ <Tool\r
+ Name="VCResourceCompilerTool"\r
+ PreprocessorDefinitions="NDEBUG"\r
+ Culture="1033"\r
+ AdditionalIncludeDirectories="../"/>\r
+ <Tool\r
+ Name="VCWebServiceProxyGeneratorTool"/>\r
+ <Tool\r
+ Name="VCXMLDataGeneratorTool"/>\r
+ <Tool\r
+ Name="VCWebDeploymentTool"/>\r
+ <Tool\r
+ Name="VCManagedWrapperGeneratorTool"/>\r
+ <Tool\r
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+ </Configuration>\r
+ </Configurations>\r
+ <References>\r
+ </References>\r
+ <Files>\r
+ <Filter\r
+ Name="Source Files"\r
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">\r
+ <File\r
+ RelativePath="ConfigDialog.cpp">\r
+ <FileConfiguration\r
+ Name="Debug|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ PreprocessorDefinitions=""/>\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Release|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="2"\r
+ PreprocessorDefinitions=""/>\r
+ </FileConfiguration>\r
+ </File>\r
+ <File\r
+ RelativePath="ConfigPropertySheet.cpp">\r
+ <FileConfiguration\r
+ Name="Debug|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ PreprocessorDefinitions=""/>\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Release|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="2"\r
+ PreprocessorDefinitions=""/>\r
+ </FileConfiguration>\r
+ </File>\r
+ <File\r
+ RelativePath=".\ControlPanelExe.cpp">\r
+ </File>\r
+ <File\r
+ RelativePath="FirstPage.cpp">\r
+ <FileConfiguration\r
+ Name="Debug|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ PreprocessorDefinitions=""/>\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Release|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="2"\r
+ PreprocessorDefinitions=""/>\r
+ </FileConfiguration>\r
+ </File>\r
+ <File\r
+ RelativePath="SecondPage.cpp">\r
+ <FileConfiguration\r
+ Name="Debug|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ PreprocessorDefinitions=""/>\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Release|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="2"\r
+ PreprocessorDefinitions=""/>\r
+ </FileConfiguration>\r
+ </File>\r
+ <File\r
+ RelativePath="SharedSecret.cpp">\r
+ </File>\r
+ <File\r
+ RelativePath="stdafx.cpp">\r
+ <FileConfiguration\r
+ Name="Debug|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="0"\r
+ PreprocessorDefinitions=""\r
+ UsePrecompiledHeader="0"/>\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Release|Win32">\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ Optimization="2"\r
+ PreprocessorDefinitions=""\r
+ UsePrecompiledHeader="0"/>\r
+ </FileConfiguration>\r
+ </File>\r
+ <File\r
+ RelativePath="ThirdPage.cpp">\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Header Files"\r
+ Filter="h;hpp;hxx;hm;inl">\r
+ <File\r
+ RelativePath="..\CommonServices.h">\r
+ </File>\r
+ <File\r
+ RelativePath="ConfigDialog.h">\r
+ </File>\r
+ <File\r
+ RelativePath="ConfigPropertySheet.h">\r
+ </File>\r
+ <File\r
+ RelativePath=".\ControlPanelExe.h">\r
+ </File>\r
+ <File\r
+ RelativePath="FirstPage.h">\r
+ </File>\r
+ <File\r
+ RelativePath="Resource.h">\r
+ </File>\r
+ <File\r
+ RelativePath="SecondPage.h">\r
+ </File>\r
+ <File\r
+ RelativePath="SharedSecret.h">\r
+ </File>\r
+ <File\r
+ RelativePath="stdafx.h">\r
+ </File>\r
+ <File\r
+ RelativePath="ThirdPage.h">\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Resource Files"\r
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe">\r
+ <File\r
+ RelativePath="res\configurator.ico">\r
+ </File>\r
+ <File\r
+ RelativePath="res\controlpanel.ico">\r
+ </File>\r
+ <File\r
+ RelativePath="ControlPanelExe.rc">\r
+ </File>\r
+ <File\r
+ RelativePath="res\ControlPanelExe.rc2">\r
+ </File>\r
+ <File\r
+ RelativePath="res\failure.ico">\r
+ </File>\r
+ <File\r
+ RelativePath="res\success.ico">\r
+ </File>\r
+ </Filter>\r
+ <Filter\r
+ Name="Support"\r
+ Filter="">\r
+ <File\r
+ RelativePath="..\DebugServices.c">\r
+ </File>\r
+ <File\r
+ RelativePath="..\DebugServices.h">\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\mDNSShared\dns_sd.h">\r
+ </File>\r
+ <File\r
+ RelativePath="..\WinServices.cpp">\r
+ </File>\r
+ <File\r
+ RelativePath="..\WinServices.h">\r
+ </File>\r
+ </Filter>\r
+ </Files>\r
+ <Globals>\r
+ </Globals>\r
+</VisualStudioProject>\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: FirstPage.cpp,v $
+Revision 1.6 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.5 2005/10/05 20:46:50 herscher
<rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: FirstPage.h,v $
+Revision 1.4 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/03/07 18:27:42 shersche
<rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: SecondPage.cpp,v $
+Revision 1.7 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.6 2005/10/05 20:46:50 herscher
<rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: SecondPage.h,v $
+Revision 1.5 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.4 2005/04/05 03:52:14 shersche
<rdar://problem/4066485> Registering with shared secret key doesn't work. Additionally, mDNSResponder wasn't dynamically re-reading it's DynDNS setup after setting a shared secret key.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: SharedSecret.cpp,v $
+Revision 1.6 2007/06/12 20:06:06 herscher
+<rdar://problem/5263387> ControlPanel was inadvertently adding a trailing dot to all key names.
+
+Revision 1.5 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.4 2005/10/18 06:13:41 herscher
<rdar://problem/4192119> Prepend "$" to key name to ensure that secure updates work if the domain name and key name are the same
// If there isn't a trailing dot, add one because the mDNSResponder
// presents names with the trailing dot.
- if ( zone.ReverseFind( '.' ) != zone.GetLength() )
+ if ( zone.ReverseFind( '.' ) != ( zone.GetLength() - 1 ) )
{
zone += '.';
}
- if ( m_key.ReverseFind( '.' ) != m_key.GetLength() )
+ if ( m_key.ReverseFind( '.' ) != ( m_key.GetLength() - 1 ) )
{
m_key += '.';
}
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: SharedSecret.h,v $
+Revision 1.4 2006/08/14 23:25:28 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/04/06 02:04:49 shersche
<rdar://problem/4066485> Registering with shared secret doesn't work
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ThirdPage.cpp,v $
+Revision 1.5 2006/08/14 23:25:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.4 2005/10/05 20:46:50 herscher
<rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ThirdPage.h,v $
+Revision 1.3 2006/08/14 23:25:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/03/03 19:55:21 shersche
<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
#include <DebugServices.h>
#include <list>
-#include "afxcmn.h"\r
-#include "afxwin.h"\r
+#include "afxcmn.h"
+
+#include "afxwin.h"
+
+
+
-\r
//---------------------------------------------------------------------------------------------------------------------------
// CThirdPage
BOOL m_modified;
public:
-private:\r
- static int CALLBACK \r
- SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);\r
-\r
- CListCtrl m_browseListCtrl;\r
- bool m_initialized;\r
- bool m_firstTime;\r
-\r
-public:\r
-\r
- afx_msg void OnBnClickedAddBrowseDomain();\r
- afx_msg void OnBnClickedRemoveBrowseDomain();\r
- afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);\r
- CButton m_removeButton;\r
-};\r
-\r
-\r
+private:
+
+ static int CALLBACK
+
+ SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+
+
+
+ CListCtrl m_browseListCtrl;
+
+ bool m_initialized;
+
+ bool m_firstTime;
+
+
+
+public:
+
+
+
+ afx_msg void OnBnClickedAddBrowseDomain();
+
+ afx_msg void OnBnClickedRemoveBrowseDomain();
+
+ afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
+
+ CButton m_removeButton;
+
+};
+
+
+
+
+
//---------------------------------------------------------------------------------------------------------------------------
// CAddBrowseDomain
//---------------------------------------------------------------------------------------------------------------------------
-\r
-class CAddBrowseDomain : public CDialog\r
-{\r
- DECLARE_DYNAMIC(CAddBrowseDomain)\r
-\r
-public:\r
- CAddBrowseDomain(CWnd* pParent = NULL); // standard constructor\r
- virtual ~CAddBrowseDomain();\r
-\r
-// Dialog Data\r
- enum { IDD = IDR_ADD_BROWSE_DOMAIN };\r
-\r
-protected:\r
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support\r
- virtual BOOL OnInitDialog();\r
- virtual void OnOK();\r
- DECLARE_MESSAGE_MAP()\r
-public:\r
- CComboBox m_comboBox;\r
- CString m_text;\r
-};\r
+
+
+class CAddBrowseDomain : public CDialog
+
+{
+
+ DECLARE_DYNAMIC(CAddBrowseDomain)
+
+
+
+public:
+
+ CAddBrowseDomain(CWnd* pParent = NULL); // standard constructor
+
+ virtual ~CAddBrowseDomain();
+
+
+
+// Dialog Data
+
+ enum { IDD = IDR_ADD_BROWSE_DOMAIN };
+
+
+
+protected:
+
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+
+ virtual BOOL OnInitDialog();
+
+ virtual void OnOK();
+
+ DECLARE_MESSAGE_MAP()
+
+public:
+
+ CComboBox m_comboBox;
+
+ CString m_text;
+
+};
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
+ <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" />
+ </dependentAssembly>
+ </dependency>
+</assembly>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
+ <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" />
+ </dependentAssembly>
+ </dependency>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+</assembly>
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: stdafx.cpp,v $
+Revision 1.3 2006/08/14 23:25:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/03/03 19:55:22 shersche
<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: stdafx.h,v $
+Revision 1.4 2006/08/14 23:25:29 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/10/19 19:50:35 herscher
Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
-#include <afxdlgs.h>\r
-#include <cpl.h> // Control Panel Applet functions and defines\r
+#include <afxdlgs.h>
+
+#include <cpl.h> // Control Panel Applet functions and defines
+
#include <afxtempl.h> // MFC Template support
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: AssemblyInfo.cpp,v $
+Revision 1.5 2006/08/14 23:25:43 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.4 2004/07/26 21:03:00 shersche
enable strong naming for dnssd.NET assembly
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: PString.h,v $
+Revision 1.3 2006/08/14 23:25:43 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/19 16:08:56 shersche
fix problems in UTF8/Unicode string translations
{
Byte unicodeBytes[] = Encoding::Unicode->GetBytes(string);
Byte utf8Bytes[] = Encoding::Convert(Encoding::Unicode, Encoding::UTF8, unicodeBytes);
- m_p = Marshal::AllocHGlobal(utf8Bytes->Length + 1);\r
+ m_p = Marshal::AllocHGlobal(utf8Bytes->Length + 1);
+
Byte __pin * p = &utf8Bytes[0];
char * hBytes = static_cast<char*>(m_p.ToPointer());
memcpy(hBytes, p, utf8Bytes->Length);
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Stdafx.cpp,v $
+Revision 1.3 2006/08/14 23:25:43 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/02/05 02:37:01 cheshire
Convert newlines to Unix-style (ASCII 10)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Stdafx.h,v $
+Revision 1.5 2006/08/14 23:25:43 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.4 2005/10/19 19:50:35 herscher
Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: dnssd_NET.cpp,v $
+Revision 1.10 2006/08/14 23:25:43 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.9 2004/09/16 18:17:13 shersche
Use background threads, cleanup to parameter names.
Submitted by: prepin@gmail.com
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
*
* NOTE:
Change History (most recent first):
$Log: dnssd_NET.h,v $
+Revision 1.9 2006/08/14 23:25:43 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.8 2005/02/10 22:35:33 cheshire
<rdar://problem/3727944> Update name
BEGIN
BLOCK "040904b0"
BEGIN
- VALUE "CompanyName", "Apple Computer, Inc."
+ VALUE "CompanyName", MASTER_COMPANY_NAME
VALUE "FileDescription", "Bonjour.NET Client Library"
VALUE "FileVersion", MASTER_PROD_VERS_STR
VALUE "InternalName", "dnssd.NET.dll"
BEGIN
BLOCK "040904b0"
BEGIN
- VALUE "CompanyName", "Apple Computer, Inc."
+ VALUE "CompanyName", MASTER_COMPANY_NAME
VALUE "FileDescription", "Bonjour Client Library"
VALUE "FileVersion", MASTER_PROD_VERS_STR
VALUE "InternalName", "dnssd.dll"
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: dllmain.c,v $
+Revision 1.4 2006/08/14 23:25:41 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/07/07 19:18:29 shersche
Fix error in previous checkin, change SystemServiceIsDisabled() to IsSystemServiceDisabled()
+; -*- tab-width: 4 -*-
;
; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
;
-; @APPLE_LICENSE_HEADER_START@
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
;
-; This file contains Original Code and/or Modifications of Original Code
-; as defined in and that are subject to the Apple Public Source License
-; Version 2.0 (the 'License'). You may not use this file except in
-; compliance with the License. Please obtain a copy of the License at
-; http://www.opensource.apple.com/apsl/ and read it before using this
-; file.
+; http://www.apache.org/licenses/LICENSE-2.0
;
-; The Original Code and all software distributed under the License are
-; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-; Please see the License for the specific language governing rights and
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
; limitations under the License.
-;
-; @APPLE_LICENSE_HEADER_END@
;
; Change History (most recent first):
;
; $Log: dnssd.def,v $
+; Revision 1.4 2006/09/27 00:46:18 herscher
+; <rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
+;
+; Revision 1.3 2006/08/14 23:25:41 cheshire
+; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+;
; Revision 1.2 2004/07/19 07:43:59 shersche
; export TXTRecord APIs
;
DNSServiceRegisterRecord
DNSServiceQueryRecord
DNSServiceReconfirmRecord
+ DNSServiceNATPortMappingCreate
+ DNSServiceGetAddrInfo
TXTRecordCreate
TXTRecordDeallocate
TXTRecordSetValue
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
<File\r
- RelativePath="..\DebugServices.c">\r
+ RelativePath="..\..\mDNSShared\DebugServices.c">\r
</File>\r
<File\r
RelativePath=".\dllmain.c">\r
Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
<File\r
- RelativePath="..\CommonServices.h">\r
+ RelativePath="..\..\mDNSShared\CommonServices.h">\r
</File>\r
<File\r
- RelativePath="..\DebugServices.h">\r
+ RelativePath="..\..\mDNSShared\DebugServices.h">\r
</File>\r
<File\r
RelativePath="..\..\mDNSShared\dns_sd.h">\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Application.rc2,v $
+Revision 1.3 2006/08/14 23:25:48 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:26 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: AboutDialog.cpp,v $
+Revision 1.3 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:26 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: AboutDialog.h,v $
+Revision 1.3 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:26 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Application.cpp,v $
+Revision 1.3 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:26 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Application.h,v $
+Revision 1.3 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:26 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ChooserDialog.cpp,v $
+Revision 1.4 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/02/10 22:35:35 cheshire
<rdar://problem/3727944> Update name
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: ChooserDialog.h,v $
+Revision 1.3 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:26 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: LoginDialog.cpp,v $
+Revision 1.2 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/06/18 04:04:36 rpantos
Move up one level
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: LoginDialog.h,v $
+Revision 1.2 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/06/18 04:04:36 rpantos
Move up one level
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: StdAfx.cpp,v $
+Revision 1.3 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:26 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: StdAfx.h,v $
+Revision 1.3 2006/08/14 23:25:49 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:26 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Application.cpp,v $
+Revision 1.3 2006/08/14 23:25:55 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:27 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Application.h,v $
+Revision 1.3 2006/08/14 23:25:55 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:27 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: BrowserDialog.cpp,v $
+Revision 1.3 2006/08/14 23:25:55 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:27 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: BrowserDialog.h,v $
+Revision 1.3 2006/08/14 23:25:55 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:27 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: StdAfx.cpp,v $
+Revision 1.3 2006/08/14 23:25:55 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:27 rpantos
Fix for <rdar://problem/3701120>.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: StdAfx.h,v $
+Revision 1.3 2006/08/14 23:25:55 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2004/07/13 21:24:27 rpantos
Fix for <rdar://problem/3701120>.
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: Tool.c,v $
-Revision 1.3 2004/09/16 01:58:25 cheshire
-Fix compiler warnings
-
-Revision 1.2 2004/07/13 21:24:28 rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1 2004/06/18 04:07:54 rpantos
-Move up one level
-
-Revision 1.12 2004/04/09 21:03:15 bradley
-Changed port numbers to use network byte order for consistency with other platforms.
-
-Revision 1.11 2004/01/30 03:04:32 bradley
-Updated for latest changes to mDNSWindows.
-
-Revision 1.10 2003/10/31 12:18:31 bradley
-Added display of the resolved host name. Show separate TXT record entries on separate lines.
-
-Revision 1.9 2003/10/22 02:00:20 bradley
-Fixed proxy IP setup to be in network byte order so it works on Mac and Windows.
-
-Revision 1.8 2003/10/04 04:47:08 bradley
-Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
-
-Revision 1.7 2003/08/20 07:06:34 bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.6 2003/08/20 06:50:55 bradley
-Updated to latest internal version of the mDNSCore code: Re-did everything to support
-the latest DNSServices APIs (proxies, record updates, etc.); Added support for testing the platform
-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
-
-*/
-
-#if( defined( _MSC_VER ) )
- #pragma warning( disable:4068 ) // Disable "unknown pragma" warning for "pragma unused".
- #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
- #pragma warning( disable:4311 ) // Disable "type cast : pointer truncation from void *const to int".
-
- // No stdint.h with Visual C++ so emulate it here.
-
- typedef signed char int8_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef unsigned char uint8_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef signed short int16_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef unsigned short uint16_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef signed long int32_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef unsigned long uint32_t; // C99 stdint.h not supported in VC++/VS.NET yet.
-#else
- #include <stdint.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#if( __MACH__ )
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
-
- #include <signal.h>
- #include <unistd.h>
-
- #include <CoreServices/CoreServices.h>
-#else
- #define WIN32_LEAN_AND_MEAN
-
- #include <winsock2.h>
- #include <windows.h>
-#endif
-
-#include "DNSServices.h"
-#include "DNSServiceDiscovery.h"
-
-//===========================================================================================================================
-// Macros
-//===========================================================================================================================
-
-#if( !TARGET_OS_MAC )
- #define require_action_string( X, LABEL, ACTION, STR ) \
- do \
- { \
- if( !( X ) ) \
- { \
- fprintf( stderr, "%s\n", ( STR ) ); \
- { ACTION; } \
- goto LABEL; \
- } \
- } while( 0 )
-
- #define require_string( X, LABEL, STR ) \
- do \
- { \
- if( !( X ) ) \
- { \
- fprintf( stderr, "%s\n", ( STR ) ); \
- goto LABEL; \
- \
- } \
- } while( 0 )
-
- #define require_noerr_string( ERR, LABEL, STR ) \
- do \
- { \
- if( ( ERR ) != 0 ) \
- { \
- fprintf( stderr, "%s (%ld)\n", ( STR ), ( ERR ) ); \
- goto LABEL; \
- } \
- } while( 0 )
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-int main( int argc, char* argv[] );
-static void Usage( void );
-static int ProcessArgs( int argc, char* argv[] );
-static DNSStatus ProcessPreset( int inPreset );
-
-#if( __MACH__ )
- static void SigIntHandler( int inSignalNumber );
-#endif
-
-#if( defined( WINVER ) )
- static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent );
-#endif
-
-static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inStatusCode, const DNSBrowserEvent *inEvent );
-static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus inStatusCode, const DNSResolverEvent *inEvent );
-
-static void
- RegistrationCallBack(
- void * inContext,
- DNSRegistrationRef inRef,
- DNSStatus inStatusCode,
- const DNSRegistrationEvent * inEvent );
-
-static void
- HostRegistrationCallBack(
- void * inContext,
- DNSHostRegistrationRef inRef,
- DNSStatus inStatusCode,
- void * inData );
-
-static void
- EmulatedBrowserCallBack(
- DNSServiceBrowserReplyResultType inResult,
- const char * inName,
- const char * inType,
- const char * inDomain,
- DNSServiceDiscoveryReplyFlags inFlags,
- void * inContext );
-
-static void
- EmulatedDomainEnumerationCallBack(
- DNSServiceDomainEnumerationReplyResultType inResult,
- const char * inDomain,
- DNSServiceDiscoveryReplyFlags inFlags,
- void * inContext );
-
-static void
- EmulatedResolverCallBack(
- struct sockaddr * inInterfaceAddr,
- struct sockaddr * inAddr,
- const char * inTextRecord,
- DNSServiceDiscoveryReplyFlags inFlags,
- void * inContext );
-
-static void EmulatedRegistrationCallBack( DNSServiceRegistrationReplyErrorType inResult, void *inContext );
-
-static char * IPv4ToString( DNSOpaque32 inIP, char *outString );
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-#if( defined( WINVER ) )
- static volatile int gQuit = 0;
-#endif
-
-static int gPrintTXTRecords = 1;
-
-// Presets
-
-typedef struct PresetData PresetData;
-struct PresetData
-{
- int argc;
- char * argv[ 16 ];
-};
-
-#if 0
-#pragma mark == Presets ==
-#endif
-
-static const PresetData gPresets[] =
-{
- /* 01 */ { 2, { "DNSServiceTest", "-bbd" } },
- /* 02 */ { 4, { "DNSServiceTest", "-bs", "_airport._tcp", "local." } },
- /* 03 */ { 4, { "DNSServiceTest", "-bs", "_xserveraid._tcp", "local." } },
- /* 04 */ { 3, { "DNSServiceTest", "-rdb", "apple.com" } },
- /* 05 */ { 7, { "DNSServiceTest", "-rs", "My Fake AirPort", "_airport._tcp", "local.", "1234", "My Fake Info" } },
- /* 06 */ { 7, { "DNSServiceTest", "-rs", "My Fake Xserve RAID", "_xserveraid._tcp", "local.", "1234", "My Fake Info" } },
- /* 07 */ { 7, { "DNSServiceTest", "-rs", "My Fake Web Server", "_http._tcp", "local.", "8080", "index.html" } },
- /* 08 */ { 9, { "DNSServiceTest", "-rps", "www.apple.com", "17.254.0.91", "Apple Web Server", "_http._tcp", "local.", "80", "index.html" } },
-};
-
-const int gPresetsCount = sizeof( gPresets ) / sizeof( gPresets[ 0 ] );
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// main
-//===========================================================================================================================
-
-int main( int argc, char* argv[] )
-{
- DNSStatus err;
-
- // Set up DNS Services and install a Console Control Handler to handle things like control-c signals.
-
- err = DNSServicesInitialize( kDNSFlagAdvertise, 0 );
- require_noerr_string( err, exit, "could not initialize DNSServiceTest" );
-
-#if( __MACH__ )
- signal( SIGINT, SigIntHandler );
-#endif
-
-#if( defined( WINVER ) )
- SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
-#endif
-
- ProcessArgs( argc, argv );
-
-exit:
- DNSServicesFinalize();
- return( err );
-}
-
-//===========================================================================================================================
-// Usage
-//===========================================================================================================================
-
-static void Usage( void )
-{
- fprintf( stderr, "\n" );
- fprintf( stderr, "DNSServiceTest - DNS-SD Test Tool 1.0d1\n" );
- fprintf( stderr, "\n" );
- fprintf( stderr, " -bbd 'b'rowse for 'b'rowsing 'd'omains\n" );
- fprintf( stderr, " -brd 'b'rowse for 'r'egistration 'd'omains\n" );
- fprintf( stderr, " -bs <type> <domain> 'b'rowse for 's'ervices\n" );
- fprintf( stderr, " -lsi <name> <type> <domain> 'l'ookup 's'ervice 'i'nstance\n" );
- fprintf( stderr, " -rdb[d] <domain> 'r'egister 'd'omain for 'b'rowsing ['d'efault]\n" );
- fprintf( stderr, " -rdr[d] <domain> 'r'egister 'd'omain for 'r'egistration ['d'efault]\n" );
- fprintf( stderr, " -rs <name> <type> <domain> <port> <txt> 'r'egister 's'ervice\n" );
- fprintf( stderr, " -rps <host> <ip> <name> <type> <domain> <port> <txt> 'r'egister 'p'roxy 's'ervice\n" );
- fprintf( stderr, " -rnss <name> <type> <domain> 'r'egister 'n'o 's'uch 's'ervice\n" );
-
- fprintf( stderr, " -ebs <type> <domain> 'e'mulated 'b'rowse for 's'ervices\n" );
- fprintf( stderr, " -ebd <registration/browse> 'e'mulated 'b'rowse for 'd'omains\n" );
- fprintf( stderr, " -elsi <name> <type> <domain> 'e'mulated 'l'ookup 's'ervice 'i'nstance\n" );
- fprintf( stderr, " -ers <name> <type> <domain> <port> <txt> 'e'mulated 'r'egister 's'ervice\n" );
-
- fprintf( stderr, " -h[elp] 'h'elp\n" );
- fprintf( stderr, "\n" );
-
- fprintf( stderr, " -1 Preset 1 (browse for browsing domains) DNSServiceTest -bbd\n" );
- fprintf( stderr, " -2 Preset 2 (browse for AirPort) DNSServiceTest -bs \"_airport._tcp\" \"local.\"\n" );
- fprintf( stderr, " -3 Preset 3 (browse for Xserve RAID) DNSServiceTest -bs \"_xserveraid._tcp\" \"local.\"\n" );
- fprintf( stderr, " -4 Preset 4 (register apple.com domain) DNSServiceTest -rdb \"apple.com\"\n" );
- fprintf( stderr, " -5 Preset 5 (register fake AirPort) DNSServiceTest -rs \"My Fake AirPort\" \"_airport._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
- fprintf( stderr, " -6 Preset 6 (register fake Xserve RAID) DNSServiceTest -rs \"My Fake Xserve RAID\" \"_xserveraid._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
- fprintf( stderr, " -7 Preset 7 (register fake web server) DNSServiceTest -rs \"My Fake Web Server\" \"_http._tcp\" \"local.\" 8080 \"index.html\"\n" );
- fprintf( stderr, "\n" );
-}
-
-//===========================================================================================================================
-// ProcessArgs
-//===========================================================================================================================
-
-static int ProcessArgs( int argc, char* argv[] )
-{
- DNSStatus err;
- int i;
- const char * name;
- const char * type;
- const char * domain;
- uint16_t port;
- const char * text;
- size_t textSize;
- DNSBrowserRef browser;
- DNSResolverFlags resolverFlags;
- DNSDomainRegistrationType domainType;
- const char * label;
- const char * host;
- const char * ip;
- unsigned int b[ 4 ];
- DNSNetworkAddress addr;
- dns_service_discovery_ref emulatedRef;
-
- // Parse the command line arguments (ignore first argument since it's just the program name).
-
- require_action_string( argc >= 2, exit, err = kDNSBadParamErr, "no arguments specified" );
-
- for( i = 1; i < argc; ++i )
- {
- if( strcmp( argv[ i ], "-bbd" ) == 0 )
- {
- // 'b'rowse for 'b'rowsing 'd'omains
-
- fprintf( stdout, "browsing for browsing domains\n" );
-
- err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
- require_noerr_string( err, exit, "create browser failed" );
-
- err = DNSBrowserStartDomainSearch( browser, 0 );
- require_noerr_string( err, exit, "start domain search failed" );
- }
- else if( strcmp( argv[ i ], "-brd" ) == 0 )
- {
- // 'b'rowse for 'r'egistration 'd'omains
-
- fprintf( stdout, "browsing for registration domains\n" );
-
- err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
- require_noerr_string( err, exit, "create browser failed" );
-
- err = DNSBrowserStartDomainSearch( browser, kDNSBrowserFlagRegistrationDomainsOnly );
- require_noerr_string( err, exit, "start domain search failed" );
- }
- else if( strcmp( argv[ i ], "-bs" ) == 0 )
- {
- // 'b'rowse for 's'ervices <type> <domain>
-
- require_action_string( argc > ( i + 2 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- type = argv[ i++ ];
- domain = argv[ i ];
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "browsing for \"%s.%s\"\n", type, domain );
-
- err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
- require_noerr_string( err, exit, "create browser failed" );
-
- err = DNSBrowserStartServiceSearch( browser, kDNSBrowserFlagAutoResolve, type, domain );
- require_noerr_string( err, exit, "start service search failed" );
- }
- else if( strcmp( argv[ i ], "-lsi" ) == 0 )
- {
- // 'l'ookup 's'ervice 'i'nstance <name> <type> <domain>
-
- require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- name = argv[ i++ ];
- type = argv[ i++ ];
- domain = argv[ i ];
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "resolving \"%s.%s.%s\"\n", name, type, domain );
-
- resolverFlags = kDNSResolverFlagOnlyIfUnique |
- kDNSResolverFlagAutoReleaseByName;
- err = DNSResolverCreate( resolverFlags, name, type, domain, ResolverCallBack, 0, NULL, NULL );
- require_noerr_string( err, exit, "create resolver failed" );
- }
- else if( ( strcmp( argv[ i ], "-rdb" ) == 0 ) || ( strcmp( argv[ i ], "-rdbd" ) == 0 ) )
- {
- // 'r'egister 'd'omain for 'b'rowsing ['d'efault] <domain>
-
- require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
- if( strcmp( argv[ i ], "-rdb" ) == 0 )
- {
- domainType = kDNSDomainRegistrationTypeBrowse;
- label = "";
- }
- else
- {
- domainType = kDNSDomainRegistrationTypeBrowseDefault;
- label = "default ";
- }
- ++i;
- domain = argv[ i ];
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "registering \"%s\" as %sbrowse domain\n", domain, label );
-
- err = DNSDomainRegistrationCreate( 0, domain, domainType, NULL );
- require_noerr_string( err, exit, "create domain registration failed" );
- }
- else if( ( strcmp( argv[ i ], "-rdr" ) == 0 ) || ( strcmp( argv[ i ], "-rdrd" ) == 0 ) )
- {
- // 'r'egister 'd'omain for 'r'egistration ['d'efault] <domain>
-
- require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
- if( strcmp( argv[ i ], "-rdr" ) == 0 )
- {
- domainType = kDNSDomainRegistrationTypeRegistration;
- label = "";
- }
- else
- {
- domainType = kDNSDomainRegistrationTypeRegistrationDefault;
- label = "default ";
- }
- ++i;
- domain = argv[ i ];
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "registering \"%s\" as %sregistration domain\n", domain, label );
-
- err = DNSDomainRegistrationCreate( 0, domain, domainType, NULL );
- require_noerr_string( err, exit, "create domain registration failed" );
- }
- else if( strcmp( argv[ i ], "-rs" ) == 0 )
- {
- // 'r'egister 's'ervice <name> <type> <domain> <port> <txt>
-
- require_action_string( argc > ( i + 5 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- name = argv[ i++ ];
- type = argv[ i++ ];
- domain = argv[ i++ ];
- port = (uint16_t) atoi( argv[ i++ ] );
- text = argv[ i ];
- textSize = strlen( text );
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
-
- err = DNSRegistrationCreate( 0, name, type, domain, (DNSPort) port, text, (DNSCount) textSize, NULL, NULL,
- RegistrationCallBack, NULL, NULL );
- require_noerr_string( err, exit, "create registration failed" );
- }
- else if( strcmp( argv[ i ], "-rps" ) == 0 )
- {
- DNSHostRegistrationFlags hostFlags;
-
- // 'r'egister 'p'roxy 's'ervice <host> <ip> <name> <type> <domain> <port> <txt>
-
- require_action_string( argc > ( i + 7 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- host = argv[ i++ ];
- ip = argv[ i++ ];
- name = argv[ i++ ];
- type = argv[ i++ ];
- domain = argv[ i++ ];
- port = (uint16_t) atoi( argv[ i++ ] );
- text = argv[ i ];
- textSize = strlen( text );
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
-
- sscanf( ip, "%u.%u.%u.%u", &b[ 0 ], &b[ 1 ], &b[ 2 ], &b[ 3 ] );
- addr.addressType = kDNSNetworkAddressTypeIPv4;
- addr.u.ipv4.addr.v8[ 0 ] = (DNSUInt8) b[ 0 ];
- addr.u.ipv4.addr.v8[ 1 ] = (DNSUInt8) b[ 1 ];
- addr.u.ipv4.addr.v8[ 2 ] = (DNSUInt8) b[ 2 ];
- addr.u.ipv4.addr.v8[ 3 ] = (DNSUInt8) b[ 3 ];
-
- fprintf( stdout, "registering proxy service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
-
- hostFlags = kDNSHostRegistrationFlagOnlyIfNotFound | kDNSHostRegistrationFlagAutoRenameOnConflict;
- err = DNSHostRegistrationCreate( hostFlags, host, domain, &addr, NULL,
- HostRegistrationCallBack, NULL, NULL );
- require_noerr_string( err, exit, "create host registration failed" );
-
- err = DNSRegistrationCreate( 0, name, type, domain, (DNSPort) port, text, (DNSCount) textSize, host, NULL,
- RegistrationCallBack, NULL, NULL );
- require_noerr_string( err, exit, "create registration failed" );
- }
- else if( strcmp( argv[ i ], "-rnss" ) == 0 )
- {
- // 'r'egister 'n'o 's'uch 's'ervice <name> <type> <domain>
-
- require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- name = argv[ i++ ];
- type = argv[ i++ ];
- domain = argv[ i++ ];
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "registering no-such-service \"%s.%s.%s\"\n", name, type, domain );
-
- err = DNSNoSuchServiceRegistrationCreate( 0, name, type, domain, NULL, RegistrationCallBack, NULL, NULL );
- require_noerr_string( err, exit, "create no-such-service registration failed" );
- }
- else if( strcmp( argv[ i ], "-ebs" ) == 0 )
- {
- // 'e'mulated 'b'rowse for 's'ervices <type> <domain>
-
- require_action_string( argc > ( i + 2 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- type = argv[ i++ ];
- domain = argv[ i ];
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "emulated browsing for \"%s.%s\"\n", type, domain );
-
- emulatedRef = DNSServiceBrowserCreate( type, domain, EmulatedBrowserCallBack, NULL );
- require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated browser failed" );
- }
- else if( strcmp( argv[ i ], "-ebd" ) == 0 )
- {
- int registrationOnly;
-
- // 'e'mulated 'b'rowse for 'd'omains <registration/browse>
-
- require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- type = argv[ i++ ];
- if( strcmp( type, "registration" ) == 0 )
- {
- registrationOnly = 1;
- }
- else if( strcmp( type, "browse" ) == 0 )
- {
- registrationOnly = 0;
- }
- else
- {
- require_action_string( 0, exit, err = kDNSBadParamErr, "invalid browse type" );
- }
- fprintf( stdout, "emulated browsing for %s domains\n", type );
-
- emulatedRef = DNSServiceDomainEnumerationCreate( registrationOnly, EmulatedDomainEnumerationCallBack, NULL );
- require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated domain browser failed" );
- }
- else if( strcmp( argv[ i ], "-elsi" ) == 0 )
- {
- // 'e'mulated 'l'ookup 's'ervice 'i'nstance <name> <type> <domain>
-
- require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- name = argv[ i++ ];
- type = argv[ i++ ];
- domain = argv[ i ];
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "emulated resolving \"%s.%s.%s\"\n", name, type, domain );
-
- emulatedRef = DNSServiceResolverResolve( name, type, domain, EmulatedResolverCallBack, NULL );
- require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated resolver failed" );
- }
- else if( strcmp( argv[ i ], "-ers" ) == 0 )
- {
- // 'e'mulated 'r'egister 's'ervice <name> <type> <domain> <port> <txt>
-
- require_action_string( argc > ( i + 5 ), exit, err = kDNSBadParamErr, "missing arguments" );
- ++i;
- name = argv[ i++ ];
- type = argv[ i++ ];
- domain = argv[ i++ ];
- port = (uint16_t) atoi( argv[ i++ ] );
- text = argv[ i ];
- textSize = strlen( text );
- if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
- {
- domain = "local.";
- }
- fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
-
- emulatedRef = DNSServiceRegistrationCreate( name, type, domain, htons( port ), text,
- EmulatedRegistrationCallBack, NULL );
- require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated registration failed" );
- }
- else if( ( argv[ i ][ 0 ] == '-' ) && isdigit( argv[ i ][ 1 ] ) )
- {
- // Preset
-
- ProcessPreset( atoi( &argv[ i ][ 1 ] ) );
- err = 0;
- goto exit;
- }
- else if( strcmp( argv[ i ], "-q" ) == 0 )
- {
- // Quiet (no text records)
-
- gPrintTXTRecords = 0;
- }
- else if( ( strcmp( argv[ i ], "-help" ) == 0 ) || ( strcmp( argv[ i ], "-h" ) == 0 ) )
- {
- // Help
-
- Usage();
- err = 0;
- goto exit;
- }
- else
- {
- // Unknown parameter.
-
- require_action_string( 0, exit, err = kDNSBadParamErr, "unknown parameter" );
- goto exit;
- }
- }
-
- // Run until control-C'd.
-
- #if( __MACH__ )
- CFRunLoopRun();
- #endif
-
- #if( defined( WINVER ) )
- while( !gQuit )
- {
- Sleep( 200 );
- }
- #endif
-
- err = kDNSNoErr;
-
-exit:
- if( err )
- {
- Usage();
- }
- return( err );
-}
-
-//===========================================================================================================================
-// ProcessPreset
-//===========================================================================================================================
-
-static DNSStatus ProcessPreset( int inPreset )
-{
- DNSStatus err;
-
- require_action_string( ( inPreset > 0 ) && ( inPreset <= gPresetsCount ), exit, err = kDNSBadParamErr, "invalid preset" );
-
- err = ProcessArgs( gPresets[ inPreset - 1 ].argc, (char **) gPresets[ inPreset - 1 ].argv );
-
-exit:
- return( err );
-}
-
-#if( __MACH__ )
-//===========================================================================================================================
-// SigIntHandler
-//===========================================================================================================================
-
-static void SigIntHandler( int inSignalNumber )
-{
- DNS_UNUSED( inSignalNumber );
-
- signal( SIGINT, SIG_DFL );
- CFRunLoopStop( CFRunLoopGetCurrent() );
-}
-#endif
-
-#if( defined( WINVER ) )
-//===========================================================================================================================
-// ConsoleControlHandler
-//===========================================================================================================================
-
-static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent )
-{
- BOOL handled;
-
- handled = 0;
- switch( inControlEvent )
- {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- case CTRL_CLOSE_EVENT:
- case CTRL_LOGOFF_EVENT:
- case CTRL_SHUTDOWN_EVENT:
- gQuit = 1;
- handled = 1;
- break;
-
- default:
- break;
- }
- return( handled );
-}
-#endif
-
-//===========================================================================================================================
-// BrowserCallBack
-//===========================================================================================================================
-
-static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inStatusCode, const DNSBrowserEvent *inEvent )
-{
- char ifIP[ 32 ];
- char ip[ 32 ];
-
- DNS_UNUSED( inContext );
- DNS_UNUSED( inRef );
- DNS_UNUSED( inStatusCode );
-
- switch( inEvent->type )
- {
- case kDNSBrowserEventTypeRelease:
- break;
-
- case kDNSBrowserEventTypeAddDomain:
- fprintf( stdout, "domain \"%s\" added on interface 0x%p (%s)\n",
- inEvent->data.addDomain.domain,
- (int) inEvent->data.addDomain.interfaceID,
- IPv4ToString( inEvent->data.addDomain.interfaceIP.u.ipv4.addr, ifIP ) );
- break;
-
- case kDNSBrowserEventTypeAddDefaultDomain:
- fprintf( stdout, "default domain \"%s\" added on interface 0x%p (%s)\n",
- inEvent->data.addDefaultDomain.domain,
- (int) inEvent->data.addDefaultDomain.interfaceID,
- IPv4ToString( inEvent->data.addDefaultDomain.interfaceIP.u.ipv4.addr, ifIP ) );
- break;
-
- case kDNSBrowserEventTypeRemoveDomain:
- fprintf( stdout, "domain \"%s\" removed on interface 0x%p (%s)\n",
- inEvent->data.removeDomain.domain,
- (int) inEvent->data.removeDomain.interfaceID,
- IPv4ToString( inEvent->data.removeDomain.interfaceIP.u.ipv4.addr, ifIP ) );
- break;
-
- case kDNSBrowserEventTypeAddService:
- fprintf( stdout, "service \"%s.%s%s\" added on interface 0x%p (%s)\n",
- inEvent->data.addService.name,
- inEvent->data.addService.type,
- inEvent->data.addService.domain,
- (int) inEvent->data.addService.interfaceID,
- IPv4ToString( inEvent->data.addService.interfaceIP.u.ipv4.addr, ifIP ) );
- break;
-
- case kDNSBrowserEventTypeRemoveService:
- fprintf( stdout, "service \"%s.%s%s\" removed on interface 0x%p (%s)\n",
- inEvent->data.removeService.name,
- inEvent->data.removeService.type,
- inEvent->data.removeService.domain,
- (int) inEvent->data.removeService.interfaceID,
- IPv4ToString( inEvent->data.removeService.interfaceIP.u.ipv4.addr, ifIP ) );
- break;
-
- case kDNSBrowserEventTypeResolved:
- {
- const uint8_t * p;
- const uint8_t * end;
- int i;
-
- fprintf( stdout, "resolved \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%p (%s)%s\n",
- inEvent->data.resolved->name,
- inEvent->data.resolved->type,
- inEvent->data.resolved->domain,
- inEvent->data.resolved->hostName,
- IPv4ToString( inEvent->data.resolved->address.u.ipv4.addr, ip ),
- ( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) |
- inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ],
- (int) inEvent->data.resolved->interfaceID,
- IPv4ToString( inEvent->data.resolved->interfaceIP.u.ipv4.addr, ifIP ),
- ( inEvent->data.resolved->textRecordRawSize > 0 ) ? " with text:" : "" );
-
- p = (const uint8_t *) inEvent->data.resolved->textRecordRaw;
- end = p + inEvent->data.resolved->textRecordRawSize;
- i = 0;
-
- if( gPrintTXTRecords )
- {
- while( p < end )
- {
- uint8_t size;
-
- size = *p++;
- if( ( p + size ) > end )
- {
- fprintf( stdout, "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
- break;
- }
- fprintf( stdout, "%5d (%3d bytes): \"%.*s\"\n", i, size, size, p );
- p += size;
- ++i;
- }
- fprintf( stdout, "\n" );
- }
- break;
- }
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// ResolverCallBack
-//===========================================================================================================================
-
-static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus inStatusCode, const DNSResolverEvent *inEvent )
-{
- char ifIP[ 32 ];
- char ip[ 32 ];
-
- DNS_UNUSED( inContext );
- DNS_UNUSED( inRef );
- DNS_UNUSED( inStatusCode );
-
- switch( inEvent->type )
- {
- case kDNSResolverEventTypeResolved:
- {
- const uint8_t * p;
- const uint8_t * end;
- int i;
-
- fprintf( stdout, "resolved \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%p (%s)%s\n",
- inEvent->data.resolved.name,
- inEvent->data.resolved.type,
- inEvent->data.resolved.domain,
- inEvent->data.resolved.hostName,
- IPv4ToString( inEvent->data.resolved.address.u.ipv4.addr, ip ),
- ( inEvent->data.resolved.address.u.ipv4.port.v8[ 0 ] << 8 ) |
- inEvent->data.resolved.address.u.ipv4.port.v8[ 1 ],
- (int) inEvent->data.resolved.interfaceID,
- IPv4ToString( inEvent->data.resolved.interfaceIP.u.ipv4.addr, ifIP ),
- ( inEvent->data.resolved.textRecordRawSize > 0 ) ? " with text:" : "" );
-
- p = (const uint8_t *) inEvent->data.resolved.textRecordRaw;
- end = p + inEvent->data.resolved.textRecordRawSize;
- i = 0;
-
- if( gPrintTXTRecords )
- {
- while( p < end )
- {
- uint8_t size;
-
- size = *p++;
- if( ( p + size ) > end )
- {
- fprintf( stdout, "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
- break;
- }
- fprintf( stdout, "%5d (%3d bytes): \"%.*s\"\n", i, size, size, p );
- p += size;
- ++i;
- }
- fprintf( stdout, "\n" );
- }
- break;
- }
-
- case kDNSResolverEventTypeRelease:
- break;
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// RegistrationCallBack
-//===========================================================================================================================
-
-static void
- RegistrationCallBack(
- void * inContext,
- DNSRegistrationRef inRef,
- DNSStatus inStatusCode,
- const DNSRegistrationEvent * inEvent )
-{
- DNS_UNUSED( inContext );
- DNS_UNUSED( inRef );
- DNS_UNUSED( inStatusCode );
-
- switch( inEvent->type )
- {
- case kDNSRegistrationEventTypeRelease:
- break;
-
- case kDNSRegistrationEventTypeRegistered:
- fprintf( stdout, "name registered and active\n" );
- break;
-
- case kDNSRegistrationEventTypeNameCollision:
- fprintf( stdout, "name in use, please choose another name\n" );
- break;
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// HostRegistrationCallBack
-//===========================================================================================================================
-
-static void
- HostRegistrationCallBack(
- void * inContext,
- DNSHostRegistrationRef inRef,
- DNSStatus inStatusCode,
- void * inData )
-{
- DNS_UNUSED( inContext );
- DNS_UNUSED( inRef );
- DNS_UNUSED( inData );
-
- if( inStatusCode == kDNSNoErr )
- {
- fprintf( stdout, "host name registered and active\n" );
- }
- else if( inStatusCode == kDNSNameConflictErr )
- {
- fprintf( stdout, "host name in use, please choose another name\n" );
- }
- else
- {
- fprintf( stdout, "unknown host registration status (%ld)\n", inStatusCode );
- }
-}
-
-//===========================================================================================================================
-// EmulatedBrowserCallBack
-//===========================================================================================================================
-
-static void
- EmulatedBrowserCallBack(
- DNSServiceBrowserReplyResultType inResult,
- const char * inName,
- const char * inType,
- const char * inDomain,
- DNSServiceDiscoveryReplyFlags inFlags,
- void * inContext )
-{
- DNS_UNUSED( inFlags );
- DNS_UNUSED( inContext );
-
- if( inResult == DNSServiceBrowserReplyAddInstance )
- {
- fprintf( stdout, "\"%s.%s%s\" service added emulated\n", inName, inType, inDomain );
- }
- else if( inResult == DNSServiceBrowserReplyRemoveInstance )
- {
- fprintf( stdout, "\"%s.%s%s\" service removed emulated\n", inName, inType, inDomain );
- }
- else
- {
- fprintf( stdout, "### unknown emulated browser callback result (%d)\n", inResult );
- }
-}
-
-//===========================================================================================================================
-// EmulatedDomainEnumerationCallBack
-//===========================================================================================================================
-
-static void
- EmulatedDomainEnumerationCallBack(
- DNSServiceDomainEnumerationReplyResultType inResult,
- const char * inDomain,
- DNSServiceDiscoveryReplyFlags inFlags,
- void * inContext )
-{
- DNS_UNUSED( inFlags );
- DNS_UNUSED( inContext );
-
- if( inResult == DNSServiceDomainEnumerationReplyAddDomain )
- {
- fprintf( stdout, "\"%s\" domain added emulated\n", inDomain );
- }
- else if( inResult == DNSServiceDomainEnumerationReplyAddDomainDefault )
- {
- fprintf( stdout, "\"%s\" default domain added emulated\n", inDomain );
- }
- else if( inResult == DNSServiceDomainEnumerationReplyRemoveDomain )
- {
- fprintf( stdout, "\"%s\" domain removed emulated\n", inDomain );
- }
- else
- {
- fprintf( stdout, "### unknown emulated domain enumeration callback result (%d)\n", inResult );
- }
-}
-
-//===========================================================================================================================
-// EmulatedResolverCallBack
-//===========================================================================================================================
-
-static void
- EmulatedResolverCallBack(
- struct sockaddr * inInterfaceAddr,
- struct sockaddr * inAddr,
- const char * inTextRecord,
- DNSServiceDiscoveryReplyFlags inFlags,
- void * inContext )
-{
- struct sockaddr_in * ifSin4;
- struct sockaddr_in * sin4;
- char ifIP[ 64 ];
- char ip[ 64 ];
-
- DNS_UNUSED( inFlags );
- DNS_UNUSED( inContext );
-
- ifSin4 = (struct sockaddr_in *) inInterfaceAddr;
- sin4 = (struct sockaddr_in *) inAddr;
-
- fprintf( stdout, "service resolved to %s:%d on interface %s with text \"%s\"\n",
- IPv4ToString( *( (DNSOpaque32 *) &sin4->sin_addr.s_addr ), ip ),
- ntohs( sin4->sin_port ),
- IPv4ToString( *( (DNSOpaque32 *) &ifSin4->sin_addr.s_addr ), ifIP ),
- inTextRecord ? inTextRecord : "" );
-}
-
-//===========================================================================================================================
-// EmulatedResolverCallBack
-//===========================================================================================================================
-
-static void EmulatedRegistrationCallBack( DNSServiceRegistrationReplyErrorType inResult, void *inContext )
-{
- DNS_UNUSED( inContext );
-
- if( inResult == kDNSServiceDiscoveryNoError )
- {
- fprintf( stdout, "service name registered successfully\n" );
- }
- else
- {
- fprintf( stdout, "service registration failed( %d)\n", inResult );
- }
-}
-
-//===========================================================================================================================
-// IPv4ToString
-//===========================================================================================================================
-
-static char * IPv4ToString( DNSOpaque32 inIP, char *outString )
-{
- sprintf( outString, "%u.%u.%u.%u", inIP.v8[ 0 ], inIP.v8[ 1 ], inIP.v8[ 2 ], inIP.v8[ 3 ] );
- return( outString );
-}
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: ToolPrefixWindows.h,v $
-Revision 1.1 2004/06/18 04:07:54 rpantos
-Move up one level
-
-Revision 1.3 2004/01/30 03:04:32 bradley
-Updated for latest changes to mDNSWindows.
-
-Revision 1.2 2003/08/20 07:06:34 bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1 2003/08/20 06:01:19 bradley
-Prefix files for CodeWarrior Windows builds to set compile options.
-
-*/
-
-#ifndef __TOOL_PREFIX_WINDOWS__
-#define __TOOL_PREFIX_WINDOWS__
-
-#define DEBUG 0
-
-#endif // __TOOL_PREFIX_WINDOWS__
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: ToolPrefixWindowsDebug.h,v $
-Revision 1.1 2004/06/18 04:07:54 rpantos
-Move up one level
-
-Revision 1.3 2004/01/30 03:04:32 bradley
-Updated for latest changes to mDNSWindows.
-
-Revision 1.2 2003/08/20 07:06:34 bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1 2003/08/20 06:01:19 bradley
-Prefix files for CodeWarrior Windows builds to set compile options.
-
-*/
-
-#ifndef __TOOL_PREFIX_WINDOWS_DEBUG__
-#define __TOOL_PREFIX_WINDOWS_DEBUG__
-
-#define DEBUG 1
-#define MDNS_DEBUGMSGS 1
-
-#endif // __TOOL_PREFIX_WINDOWS_DEBUG__
+++ /dev/null
-Microsoft Visual Studio Solution File, Format Version 7.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tool", "ToolWin32VS2002.vcproj", "{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
-EndProject
-Global
- GlobalSection(SolutionConfiguration) = preSolution
- ConfigName.0 = Debug
- ConfigName.1 = Release
- EndGlobalSection
- GlobalSection(ProjectDependencies) = postSolution
- EndGlobalSection
- GlobalSection(ProjectConfiguration) = postSolution
- {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.ActiveCfg = Debug|Win32
- {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.Build.0 = Debug|Win32
- {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.ActiveCfg = Release|Win32
- {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- EndGlobalSection
- GlobalSection(ExtensibilityAddIns) = postSolution
- EndGlobalSection
-EndGlobal
+++ /dev/null
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.00"
- Name="Tool"
- ProjectGUID="{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
- ConfigurationType="1"
- CharacterSet="1">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\DNSServices"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
- StringPooling="TRUE"
- MinimalRebuild="TRUE"
- BasicRuntimeChecks="3"
- SmallerTypeCheck="FALSE"
- RuntimeLibrary="1"
- BufferSecurityCheck="TRUE"
- ForceConformanceInForLoopScope="TRUE"
- UsePrecompiledHeader="2"
- BrowseInformation="1"
- WarningLevel="4"
- WarnAsError="TRUE"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
- OutputFile="$(OutDir)/Tool.exe"
- LinkIncremental="2"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile="$(OutDir)/Tool.pdb"
- SubSystem="1"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="Release"
- ConfigurationType="1"
- CharacterSet="1"
- WholeProgramOptimization="FALSE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="2"
- FavorSizeOrSpeed="2"
- OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\DNSServices"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
- StringPooling="TRUE"
- ExceptionHandling="FALSE"
- RuntimeLibrary="0"
- BufferSecurityCheck="FALSE"
- EnableFunctionLevelLinking="FALSE"
- DisableLanguageExtensions="FALSE"
- ForceConformanceInForLoopScope="TRUE"
- UsePrecompiledHeader="2"
- WarningLevel="4"
- WarnAsError="TRUE"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="3"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
- OutputFile="$(OutDir)/Tool.exe"
- LinkIncremental="1"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="DNSServiceTest"
- Filter="">
- <File
- RelativePath="..\..\..\mDNSCore\DNSCommon.c">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\DNSCommon.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\DNSDigest.c">
- </File>
- <File
- RelativePath="..\..\DNSServices\DNSServiceDiscovery.c">
- </File>
- <File
- RelativePath="..\..\DNSServices\DNSServiceDiscovery.h">
- </File>
- <File
- RelativePath="..\..\DNSServices\DNSServices.c">
- </File>
- <File
- RelativePath="..\..\DNSServices\DNSServices.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\mDNS.c">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\mDNSClientAPI.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\mDNSDebug.h">
- </File>
- <File
- RelativePath="..\..\mDNSWin32.c">
- </File>
- <File
- RelativePath="..\..\mDNSWin32.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\uDNS.c">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\uDNS.h">
- </File>
- </Filter>
- <File
- RelativePath="Tool.c">
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+++ /dev/null
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tool", "ToolWin32VS2003.vcproj", "{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
- ProjectSection(ProjectDependencies) = postProject
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfiguration) = preSolution
- Debug = Debug
- Release = Release
- EndGlobalSection
- GlobalSection(ProjectConfiguration) = postSolution
- {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.ActiveCfg = Debug|Win32
- {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Debug.Build.0 = Debug|Win32
- {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.ActiveCfg = Release|Win32
- {F66EFE7E-50A6-44D4-87C7-742B303BA852}.Release.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- EndGlobalSection
- GlobalSection(ExtensibilityAddIns) = postSolution
- EndGlobalSection
-EndGlobal
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="Tool"
- ProjectGUID="{F66EFE7E-50A6-44D4-87C7-742B303BA852}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
- ConfigurationType="1"
- CharacterSet="1">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\DNSServices"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
- StringPooling="TRUE"
- MinimalRebuild="TRUE"
- BasicRuntimeChecks="3"
- SmallerTypeCheck="FALSE"
- RuntimeLibrary="1"
- BufferSecurityCheck="TRUE"
- ForceConformanceInForLoopScope="TRUE"
- UsePrecompiledHeader="2"
- BrowseInformation="1"
- WarningLevel="4"
- WarnAsError="TRUE"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
- OutputFile="$(OutDir)/Tool.exe"
- LinkIncremental="2"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile="$(OutDir)/Tool.pdb"
- SubSystem="1"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="Release"
- ConfigurationType="1"
- CharacterSet="1"
- WholeProgramOptimization="FALSE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="2"
- FavorSizeOrSpeed="2"
- OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="..\..\..\mDNSCore;..\..\..\mDNSWindows;..\..\DNSServices"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
- StringPooling="TRUE"
- ExceptionHandling="FALSE"
- RuntimeLibrary="0"
- BufferSecurityCheck="FALSE"
- EnableFunctionLevelLinking="FALSE"
- DisableLanguageExtensions="FALSE"
- ForceConformanceInForLoopScope="TRUE"
- UsePrecompiledHeader="2"
- WarningLevel="4"
- WarnAsError="TRUE"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="3"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
- OutputFile="$(OutDir)/Tool.exe"
- LinkIncremental="1"
- GenerateDebugInformation="TRUE"
- SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="DNSServiceTest"
- Filter="">
- <File
- RelativePath="..\..\..\mDNSCore\DNSCommon.c">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\DNSCommon.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\DNSDigest.c">
- </File>
- <File
- RelativePath="..\..\DNSServices\DNSServiceDiscovery.c">
- </File>
- <File
- RelativePath="..\..\DNSServices\DNSServiceDiscovery.h">
- </File>
- <File
- RelativePath="..\..\DNSServices\DNSServices.c">
- </File>
- <File
- RelativePath="..\..\DNSServices\DNSServices.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\mDNS.c">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\mDNSClientAPI.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\mDNSDebug.h">
- </File>
- <File
- RelativePath="..\..\mDNSWin32.c">
- </File>
- <File
- RelativePath="..\..\mDNSWin32.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\uDNS.c">
- </File>
- <File
- RelativePath="..\..\..\mDNSCore\uDNS.h">
- </File>
- </Filter>
- <File
- RelativePath="Tool.c">
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: DNSServiceDiscovery.c,v $
-Revision 1.8 2004/09/17 01:08:58 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.7 2004/05/08 12:24:48 bradley
-Removed trailing character from zero value to fix compile error.
-
-Revision 1.6 2004/05/06 18:42:58 ksekar
-General dns_sd.h API cleanup, including the following radars:
-<rdar://problem/3592068>: Remove flags with zero value
-<rdar://problem/3479569>: Passing in NULL causes a crash.
-
-Revision 1.5 2004/01/30 02:56:34 bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.4 2003/11/14 20:59:10 cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.3 2003/10/04 04:47:08 bradley
-Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
-
-Revision 1.2 2003/08/20 07:06:34 bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1 2003/08/20 06:04:45 bradley
-Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
-
-*/
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if( macintosh || __MACH__ )
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
-
-#elif( defined( _MSC_VER ) || defined( __MWERKS__ ) )
-
- #pragma warning( disable:4054 ) // Disable "type cast : from function pointer to data pointer".
- #pragma warning( disable:4055 ) // Disable "type cast : from data pointer to function pointer".
- #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
- #pragma warning( disable:4152 ) // Disable "nonstandard extension, function/data pointer conversion in expression".
-
- #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
-
- #include <winsock2.h>
-
-#endif
-
-#include "mDNSEmbeddedAPI.h"
-#include "DNSServices.h"
-
-#include "DNSServiceDiscovery.h"
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#if 0
-#pragma mark == Constants & Types ==
-#endif
-
-//===========================================================================================================================
-// Constants & Types
-//===========================================================================================================================
-
-#define DEBUG_NAME "[DNSServiceDiscovery] "
-
-typedef enum
-{
- kDNSServiceDiscoveryObjectTypeRegistration = 1,
- kDNSServiceDiscoveryObjectTypeDomainEnumeration = 2,
- kDNSServiceDiscoveryObjectTypeBrowser = 3,
- kDNSServiceDiscoveryObjectTypeResolver = 4
-
-} DNSServiceDiscoveryObjectType;
-
-typedef struct _dns_service_discovery_t _dns_service_discovery_t;
-struct _dns_service_discovery_t
-{
- DNSServiceDiscoveryObjectType type;
- void * ref;
- void * callback;
- void * context;
-};
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//===========================================================================================================================
-// Macros
-//===========================================================================================================================
-
-// Emulate Mac OS debugging macros for non-Mac platforms.
-
-#if( !TARGET_OS_MAC )
- #define check(assertion)
- #define check_string( assertion, cstring )
- #define check_noerr(err)
- #define check_noerr_string( error, cstring )
- #define debug_string( cstring )
- #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
- #define require_string( assertion, label, string ) require(assertion, label)
- #define require_quiet( assertion, label ) require( assertion, label )
- #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
- #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
- #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
- #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
- #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
- #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
- #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
-#endif
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-DNS_LOCAL void
- DNSServiceRegistrationPrivateCallBack(
- void * inContext,
- DNSRegistrationRef inRef,
- DNSStatus inStatusCode,
- const DNSRegistrationEvent * inEvent );
-
-DNS_LOCAL void
- DNSServiceDomainEnumerationPrivateCallBack(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent );
-
-DNS_LOCAL void
- DNSServiceBrowserPrivateCallBack(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent );
-
-DNS_LOCAL void
- DNSServiceResolverPrivateCallBack(
- void * inContext,
- DNSResolverRef inRef,
- DNSStatus inStatusCode,
- const DNSResolverEvent * inEvent );
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// DNSServiceRegistrationCreate
-//===========================================================================================================================
-
-dns_service_discovery_ref
- DNSServiceRegistrationCreate(
- const char * inName,
- const char * inType,
- const char * inDomain,
- uint16_t inPort,
- const char * inTextRecord,
- DNSServiceRegistrationReply inCallBack,
- void * inContext )
-{
- DNSStatus err;
- dns_service_discovery_ref result;
- dns_service_discovery_ref obj;
- void * txt;
- size_t txtSize;
- DNSOpaque16 port;
- DNSRegistrationRef registration;
-
- result = NULL;
- txt = NULL;
- txtSize = 0;
-
- // Allocate and initialize the object.
-
- obj = (dns_service_discovery_ref) malloc( sizeof( *obj ) );
- require_action( obj, exit, err = kDNSNoMemoryErr );
-
- obj->type = kDNSServiceDiscoveryObjectTypeRegistration;
- obj->ref = NULL;
- obj->callback = inCallBack;
- obj->context = inContext;
-
- // Create the underlying registration. Build a \001-escaped text record if needed.
-
- if( inTextRecord )
- {
- err = DNSDynamicTextRecordBuildEscaped( inTextRecord, &txt, &txtSize );
- require_noerr( err, exit );
- }
-
- port.v8[ 0 ] = (DNSUInt8)( inPort >> 8 );
- port.v8[ 1 ] = (DNSUInt8)( inPort & 0xFF );
- err = DNSRegistrationCreate( kDNSRegistrationFlagPreFormattedTextRecord, inName, inType, inDomain, port.v16, txt,
- (DNSCount) txtSize, NULL, NULL, DNSServiceRegistrationPrivateCallBack, obj, ®istration );
- require_noerr( err, exit );
- obj->ref = registration;
-
- // Success!
-
- result = obj;
- obj = NULL;
-
-exit:
- if( txt )
- {
- DNSDynamicTextRecordRelease( txt );
- }
- if( obj )
- {
- DNSServiceDiscoveryDeallocate( obj );
- }
- return( result );
-}
-
-//===========================================================================================================================
-// DNSServiceRegistrationPrivateCallBack
-//===========================================================================================================================
-
-DNS_LOCAL void
- DNSServiceRegistrationPrivateCallBack(
- void * inContext,
- DNSRegistrationRef inRef,
- DNSStatus inStatusCode,
- const DNSRegistrationEvent * inEvent )
-{
- dns_service_discovery_ref obj;
- DNSServiceRegistrationReply callback;
-
- DNS_UNUSED( inRef );
- DNS_UNUSED( inStatusCode );
-
- check( inContext );
- obj = (dns_service_discovery_ref) inContext;
- check( obj->callback );
- callback = (DNSServiceRegistrationReply) obj->callback;
-
- switch( inEvent->type )
- {
- case kDNSRegistrationEventTypeRegistered:
- debugf( DEBUG_NAME "name registered and active\n" );
-
- if( callback )
- {
- callback( kDNSServiceDiscoveryNoError, obj->context );
- }
- break;
-
- case kDNSRegistrationEventTypeNameCollision:
- debugf( DEBUG_NAME "name in use, please choose another name\n" );
-
- if( callback )
- {
- callback( kDNSServiceDiscoveryNameConflict, obj->context );
- }
- break;
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// DNSServiceRegistrationAddRecord
-//===========================================================================================================================
-
-DNSRecordReference
- DNSServiceRegistrationAddRecord(
- dns_service_discovery_ref inRef,
- uint16_t inRRType,
- uint16_t inRDLength,
- const char * inRData,
- uint32_t inTTL )
-{
- DNS_UNUSED( inRef );
- DNS_UNUSED( inRRType );
- DNS_UNUSED( inRDLength );
- DNS_UNUSED( inRData );
- DNS_UNUSED( inTTL );
-
- debugf( DEBUG_NAME "DNSServiceRegistrationAddRecord is currently not supported\n" );
- return( 0 );
-}
-
-//===========================================================================================================================
-// DNSServiceRegistrationUpdateRecord
-//===========================================================================================================================
-
-DNSServiceRegistrationReplyErrorType
- DNSServiceRegistrationUpdateRecord(
- dns_service_discovery_ref inRef,
- DNSRecordReference inRecordRef,
- uint16_t inRDLength,
- const char * inRData,
- uint32_t inTTL )
-{
- DNS_UNUSED( inRef );
- DNS_UNUSED( inRecordRef );
- DNS_UNUSED( inRDLength );
- DNS_UNUSED( inRData );
- DNS_UNUSED( inTTL );
-
- debugf( DEBUG_NAME "DNSServiceRegistrationUpdateRecord is currently not supported\n" );
- return( kDNSServiceDiscoveryUnsupportedErr );
-}
-
-//===========================================================================================================================
-// DNSServiceRegistrationRemoveRecord
-//===========================================================================================================================
-
-DNSServiceRegistrationReplyErrorType
- DNSServiceRegistrationRemoveRecord(
- dns_service_discovery_ref inRef,
- DNSRecordReference inRecordRef )
-{
- DNS_UNUSED( inRef );
- DNS_UNUSED( inRecordRef );
-
- debugf( DEBUG_NAME "DNSServiceRegistrationRemoveRecord is currently not supported\n" );
- return( kDNSServiceDiscoveryUnsupportedErr );
-}
-
-//===========================================================================================================================
-// DNSServiceDomainEnumerationCreate
-//===========================================================================================================================
-
-dns_service_discovery_ref
- DNSServiceDomainEnumerationCreate(
- int inRegistrationDomains,
- DNSServiceDomainEnumerationReply inCallBack,
- void * inContext )
-{
- DNSStatus err;
- dns_service_discovery_ref result;
- dns_service_discovery_ref obj;
- DNSBrowserRef browser;
- DNSBrowserFlags flags;
-
- result = NULL;
- browser = NULL;
-
- // Allocate and initialize the object.
-
- obj = (dns_service_discovery_ref) malloc( sizeof( *obj ) );
- require_action( obj, exit, err = kDNSNoMemoryErr );
-
- obj->type = kDNSServiceDiscoveryObjectTypeDomainEnumeration;
- obj->ref = NULL;
- obj->callback = inCallBack;
- obj->context = inContext;
-
- // Create the underlying browser and start searching for domains.
-
- err = DNSBrowserCreate( 0, DNSServiceDomainEnumerationPrivateCallBack, obj, &browser );
- require_noerr( err, exit );
- obj->ref = browser;
-
- if( inRegistrationDomains )
- {
- flags = kDNSBrowserFlagRegistrationDomainsOnly;
- }
- else
- {
- flags = 0;
- }
- err = DNSBrowserStartDomainSearch( browser, flags );
- require_noerr( err, exit );
-
- // Success!
-
- result = obj;
- browser = NULL;
- obj = NULL;
-
-exit:
- if( browser )
- {
- DNSBrowserRelease( browser, 0 );
- }
- if( obj )
- {
- DNSServiceDiscoveryDeallocate( obj );
- }
- return( result );
-}
-
-//===========================================================================================================================
-// DNSServiceDomainEnumerationPrivateCallBack
-//===========================================================================================================================
-
-DNS_LOCAL void
- DNSServiceDomainEnumerationPrivateCallBack(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent )
-{
- dns_service_discovery_ref obj;
- DNSServiceDomainEnumerationReply callback;
-
- DNS_UNUSED( inRef );
- DNS_UNUSED( inStatusCode );
-
- check( inContext );
- obj = (dns_service_discovery_ref) inContext;
- check( obj->callback );
- callback = (DNSServiceDomainEnumerationReply) obj->callback;
-
- switch( inEvent->type )
- {
- case kDNSBrowserEventTypeAddDomain:
- debugf( DEBUG_NAME "add domain \"%s\"\n", inEvent->data.addDomain.domain );
-
- if( callback )
- {
- callback( DNSServiceDomainEnumerationReplyAddDomain, inEvent->data.addDomain.domain,
- 0, obj->context );
- }
- break;
-
- case kDNSBrowserEventTypeAddDefaultDomain:
- debugf( DEBUG_NAME "add default domain \"%s\"\n", inEvent->data.addDefaultDomain.domain );
-
- if( callback )
- {
- callback( DNSServiceDomainEnumerationReplyAddDomainDefault, inEvent->data.addDefaultDomain.domain,
- 0, obj->context );
- }
- break;
-
- case kDNSBrowserEventTypeRemoveDomain:
- debugf( DEBUG_NAME "add default domain \"%s\"\n", inEvent->data.removeDomain.domain );
-
- if( callback )
- {
- callback( DNSServiceDomainEnumerationReplyRemoveDomain, inEvent->data.removeDomain.domain,
- 0, obj->context );
- }
- break;
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// DNSServiceBrowserCreate
-//===========================================================================================================================
-
-dns_service_discovery_ref
- DNSServiceBrowserCreate(
- const char * inType,
- const char * inDomain,
- DNSServiceBrowserReply inCallBack,
- void * inContext )
-{
- DNSStatus err;
- dns_service_discovery_ref result;
- dns_service_discovery_ref obj;
- DNSBrowserRef browser;
-
- result = NULL;
- browser = NULL;
-
- // Allocate and initialize the object.
-
- obj = (dns_service_discovery_ref) malloc( sizeof( *obj ) );
- require_action( obj, exit, err = kDNSNoMemoryErr );
-
- obj->type = kDNSServiceDiscoveryObjectTypeBrowser;
- obj->ref = NULL;
- obj->callback = inCallBack;
- obj->context = inContext;
-
- // Create the underlying browser and start searching for domains.
-
- err = DNSBrowserCreate( 0, DNSServiceBrowserPrivateCallBack, obj, &browser );
- require_noerr( err, exit );
- obj->ref = browser;
-
- err = DNSBrowserStartServiceSearch( browser, 0, inType, inDomain );
- require_noerr( err, exit );
-
- // Success!
-
- result = obj;
- browser = NULL;
- obj = NULL;
-
-exit:
- if( browser )
- {
- DNSBrowserRelease( browser, 0 );
- }
- if( obj )
- {
- DNSServiceDiscoveryDeallocate( obj );
- }
- return( result );
-}
-
-//===========================================================================================================================
-// DNSServiceBrowserPrivateCallBack
-//===========================================================================================================================
-
-DNS_LOCAL void
- DNSServiceBrowserPrivateCallBack(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent )
-{
- dns_service_discovery_ref obj;
- DNSServiceBrowserReply callback;
-
- DNS_UNUSED( inRef );
- DNS_UNUSED( inStatusCode );
-
- check( inContext );
- obj = (dns_service_discovery_ref) inContext;
- check( obj->callback );
- callback = (DNSServiceBrowserReply) obj->callback;
-
- switch( inEvent->type )
- {
- case kDNSBrowserEventTypeAddService:
- debugf( DEBUG_NAME "add service \"%s.%s%s\"\n",
- inEvent->data.addService.name,
- inEvent->data.addService.type,
- inEvent->data.addService.domain );
-
- if( callback )
- {
- callback( DNSServiceBrowserReplyAddInstance,
- inEvent->data.addService.name,
- inEvent->data.addService.type,
- inEvent->data.addService.domain,
- 0,
- obj->context );
- }
- break;
-
- case kDNSBrowserEventTypeRemoveService:
- debugf( DEBUG_NAME "remove service \"%s.%s%s\"\n",
- inEvent->data.removeService.name,
- inEvent->data.removeService.type,
- inEvent->data.removeService.domain );
-
- if( callback )
- {
- callback( DNSServiceBrowserReplyRemoveInstance,
- inEvent->data.removeService.name,
- inEvent->data.removeService.type,
- inEvent->data.removeService.domain,
- 0,
- obj->context );
- }
- break;
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// DNSServiceResolverResolve
-//===========================================================================================================================
-
-dns_service_discovery_ref
- DNSServiceResolverResolve(
- const char * inName,
- const char * inType,
- const char * inDomain,
- DNSServiceResolverReply inCallBack,
- void * inContext )
-{
- DNSStatus err;
- dns_service_discovery_ref result;
- dns_service_discovery_ref obj;
- DNSResolverRef resolver;
-
- result = NULL;
-
- // Allocate and initialize the object.
-
- obj = (dns_service_discovery_ref) malloc( sizeof( *obj ) );
- require_action( obj, exit, err = kDNSNoMemoryErr );
-
- obj->type = kDNSServiceDiscoveryObjectTypeResolver;
- obj->ref = NULL;
- obj->callback = inCallBack;
- obj->context = inContext;
-
- // Create the underlying resolver and start searching for domains.
-
- err = DNSResolverCreate( 0, inName, inType, inDomain, DNSServiceResolverPrivateCallBack, obj, NULL, &resolver );
- require_noerr( err, exit );
- obj->ref = resolver;
-
- // Success!
-
- result = obj;
- obj = NULL;
-
-exit:
- if( obj )
- {
- DNSServiceDiscoveryDeallocate( obj );
- }
- return( result );
-}
-
-//===========================================================================================================================
-// DNSServiceResolverPrivateCallBack
-//===========================================================================================================================
-
-DNS_LOCAL void
- DNSServiceResolverPrivateCallBack(
- void * inContext,
- DNSResolverRef inRef,
- DNSStatus inStatusCode,
- const DNSResolverEvent * inEvent )
-{
- dns_service_discovery_ref obj;
- DNSServiceResolverReply callback;
- struct sockaddr_in interfaceAddr;
- struct sockaddr_in addr;
-
- DNS_UNUSED( inRef );
- DNS_UNUSED( inStatusCode );
-
- check( inContext );
- obj = (dns_service_discovery_ref) inContext;
- check( obj->callback );
- callback = (DNSServiceResolverReply) obj->callback;
-
- switch( inEvent->type )
- {
- case kDNSResolverEventTypeResolved:
- debugf( DEBUG_NAME "resolved \"%s.%s%s\"\n",
- inEvent->data.resolved.name,
- inEvent->data.resolved.type,
- inEvent->data.resolved.domain );
-
- memset( &interfaceAddr, 0, sizeof( interfaceAddr ) );
- interfaceAddr.sin_family = AF_INET;
- interfaceAddr.sin_port = 0;
- interfaceAddr.sin_addr.s_addr = inEvent->data.resolved.interfaceIP.u.ipv4.addr.v32;
-
- memset( &addr, 0, sizeof( addr ) );
- addr.sin_family = AF_INET;
- addr.sin_port = inEvent->data.resolved.address.u.ipv4.port.v16;
- addr.sin_addr.s_addr = inEvent->data.resolved.address.u.ipv4.addr.v32;
-
- if( callback )
- {
- callback( (struct sockaddr *) &interfaceAddr, (struct sockaddr *) &addr, inEvent->data.resolved.textRecord,
- 0, obj->context );
- }
- break;
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// DNSServiceDiscoveryMachPort
-//===========================================================================================================================
-
-mach_port_t DNSServiceDiscoveryMachPort( dns_service_discovery_ref inRef )
-{
- DNS_UNUSED( inRef );
-
- debugf( DEBUG_NAME "DNSServiceDiscoveryMachPort is not supported\n" );
- return( 0 );
-}
-
-//===========================================================================================================================
-// DNSServiceDiscoveryDeallocate
-//===========================================================================================================================
-
-void DNSServiceDiscoveryDeallocate( dns_service_discovery_ref inRef )
-{
- _dns_service_discovery_t * obj;
- DNSStatus err;
-
- check( inRef );
- check( inRef->ref );
-
- obj = (_dns_service_discovery_t *) inRef;
- switch( obj->type )
- {
- case kDNSServiceDiscoveryObjectTypeRegistration:
- if( inRef->ref )
- {
- err = DNSRegistrationRelease( (DNSRegistrationRef) inRef->ref, 0 );
- check_noerr( err );
- }
- free( inRef );
- break;
-
- case kDNSServiceDiscoveryObjectTypeDomainEnumeration:
- if( inRef->ref )
- {
- err = DNSBrowserRelease( (DNSBrowserRef) inRef->ref, 0 );
- check_noerr( err );
- }
- free( inRef );
- break;
-
- case kDNSServiceDiscoveryObjectTypeBrowser:
- if( inRef->ref )
- {
- err = DNSBrowserRelease( (DNSBrowserRef) inRef->ref, 0 );
- check_noerr( err );
- }
- free( inRef );
- break;
-
- case kDNSServiceDiscoveryObjectTypeResolver:
- if( inRef->ref )
- {
- err = DNSResolverRelease( (DNSResolverRef) inRef->ref, 0 );
- check_noerr( err );
- }
- free( inRef );
- break;
-
- default:
- debugf( DEBUG_NAME "unknown object type (%d)\n", obj->type );
- break;
- }
-}
-
-//===========================================================================================================================
-// DNSServiceDiscovery_handleReply
-//===========================================================================================================================
-
-void DNSServiceDiscovery_handleReply( void *inReplyMessage )
-{
- DNS_UNUSED( inReplyMessage );
-
- debugf( DEBUG_NAME "DNSServiceDiscovery_handleReply is not supported\n" );
-}
-
-#ifdef __cplusplus
- }
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: DNSServiceDiscovery.h,v $
-Revision 1.4 2004/05/06 18:42:58 ksekar
-General dns_sd.h API cleanup, including the following radars:
-<rdar://problem/3592068>: Remove flags with zero value
-<rdar://problem/3479569>: Passing in NULL causes a crash.
-
-Revision 1.3 2004/01/30 02:56:34 bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.2 2003/08/20 07:06:34 bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1 2003/08/20 06:04:45 bradley
-Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
-
-*/
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @header DNSServiceDiscovery
-
- @abstract DNSServiceDiscovery emulation using DNSServices.
-*/
-
-#ifndef __DNS_SERVICE_DISCOVERY__
-#define __DNS_SERVICE_DISCOVERY__
-
-#include <stddef.h>
-
-#if( __MACH__ )
-
- #include <mach/mach_types.h>
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/cdefs.h>
-
- #include <netinet/in.h>
-
-#elif( defined( __MWERKS__ ) )
-
- #include <stdint.h>
-
-#elif( defined( _MSC_VER ) )
-
- typedef signed char int8_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef unsigned char uint8_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef signed short int16_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef unsigned short uint16_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef signed long int32_t; // C99 stdint.h not supported in VC++/VS.NET yet.
- typedef unsigned long uint32_t; // C99 stdint.h not supported in VC++/VS.NET yet.
-
-#endif
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-// Note: The following is mostly copied from DNSServiceDiscovery.h.
-
-// Compatibility types.
-
-#if( !__MACH__ )
- typedef int mach_port_t;
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef dns_service_discovery_ref
-
- @abstract Reference to a DNS Service Discovery object.
-*/
-
-typedef struct _dns_service_discovery_t * dns_service_discovery_ref;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSServiceRegistrationReplyErrorType
-
- @abstract Error codes.
-*/
-
-typedef enum
-{
- kDNSServiceDiscoveryWaiting = 1,
- kDNSServiceDiscoveryNoError = 0,
-
- // mDNS Error codes are in the range
- // FFFE FF00 (-65792) to FFFE FFFF (-65537)
-
- kDNSServiceDiscoveryUnknownErr = -65537, // 0xFFFE FFFF
- kDNSServiceDiscoveryNoSuchNameErr = -65538,
- kDNSServiceDiscoveryNoMemoryErr = -65539,
- kDNSServiceDiscoveryBadParamErr = -65540,
- kDNSServiceDiscoveryBadReferenceErr = -65541,
- kDNSServiceDiscoveryBadStateErr = -65542,
- kDNSServiceDiscoveryBadFlagsErr = -65543,
- kDNSServiceDiscoveryUnsupportedErr = -65544,
- kDNSServiceDiscoveryNotInitializedErr = -65545,
- kDNSServiceDiscoveryNoCache = -65546,
- kDNSServiceDiscoveryAlreadyRegistered = -65547,
- kDNSServiceDiscoveryNameConflict = -65548,
- kDNSServiceDiscoveryInvalid = -65549,
- kDNSServiceDiscoveryMemFree = -65792 // 0xFFFE FF00
-
-} DNSServiceRegistrationReplyErrorType;
-
-typedef uint32_t DNSRecordReference;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!
- @function DNSServiceResolver_handleReply
-
- @param replyMsg The Mach message.
-
- @description
-
- This function should be called with the Mach message sent to the port returned by the call to DNSServiceResolverResolve.
- The reply message will be interpreted and will result in a call to the specified callout function.
-*/
-
-void DNSServiceDiscovery_handleReply( void *replyMsg );
-
-/* Service Registration */
-
-typedef void (*DNSServiceRegistrationReply) (
- DNSServiceRegistrationReplyErrorType errorCode,
- void *context
-);
-
-/*!
-@function DNSServiceRegistrationCreate
- @description Register a named service with DNS Service Discovery
- @param name The name of this service instance (e.g. "Steve's Printer")
- @param regtype The service type (e.g. "_printer._tcp." -- see
- RFC 2782 (DNS SRV) and <http://www.iana.org/assignments/port-numbers>)
- @param domain The domain in which to register the service (e.g. "apple.com.")
- @param port The local port on which this service is being offered (in network byte order)
- @param txtRecord Optional protocol-specific additional information
- @param callBack The DNSServiceRegistrationReply function to be called
- @param context A user specified context which will be passed to the callout function.
- @result A dns_registration_t
-*/
-dns_service_discovery_ref DNSServiceRegistrationCreate
-(
- const char *name,
- const char *regtype,
- const char *domain,
- uint16_t port,
- const char *txtRecord,
- DNSServiceRegistrationReply callBack,
- void *context
-);
-
-/***************************************************************************/
-/* DNS Domain Enumeration */
-
-typedef enum
-{
- DNSServiceDomainEnumerationReplyAddDomain, // Domain found
- DNSServiceDomainEnumerationReplyAddDomainDefault, // Domain found (and should be selected by default)
- DNSServiceDomainEnumerationReplyRemoveDomain, // Domain has been removed from network
-} DNSServiceDomainEnumerationReplyResultType;
-
-typedef enum
-{
- DNSServiceDiscoverReplyFlagsMoreComing,
-} DNSServiceDiscoveryReplyFlags;
-
-typedef void (*DNSServiceDomainEnumerationReply) (
- DNSServiceDomainEnumerationReplyResultType resultType, // One of DNSServiceDomainEnumerationReplyResultType
- const char *replyDomain,
- DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
- void *context
-);
-
-/*!
- @function DNSServiceDomainEnumerationCreate
- @description Asynchronously create a DNS Domain Enumerator
- @param registrationDomains A boolean indicating whether you are looking
- for recommended registration domains
- (e.g. equivalent to the AppleTalk zone list in the AppleTalk Control Panel)
- or recommended browsing domains
- (e.g. equivalent to the AppleTalk zone list in the Chooser).
- @param callBack The function to be called when domains are found or removed
- @param context A user specified context which will be passed to the callout function.
- @result A dns_registration_t
-*/
-dns_service_discovery_ref DNSServiceDomainEnumerationCreate
-(
- int registrationDomains,
- DNSServiceDomainEnumerationReply callBack,
- void *context
-);
-
-/***************************************************************************/
-/* DNS Service Browser */
-
-typedef enum
-{
- DNSServiceBrowserReplyAddInstance, // Instance of service found
- DNSServiceBrowserReplyRemoveInstance // Instance has been removed from network
-} DNSServiceBrowserReplyResultType;
-
-typedef void (*DNSServiceBrowserReply) (
- DNSServiceBrowserReplyResultType resultType, // One of DNSServiceBrowserReplyResultType
- const char *replyName,
- const char *replyType,
- const char *replyDomain,
- DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
- void *context
-);
-
-/*!
- @function DNSServiceBrowserCreate
- @description Asynchronously create a DNS Service browser
- @param regtype The type of service
- @param domain The domain in which to find the service
- @param callBack The function to be called when service instances are found or removed
- @param context A user specified context which will be passed to the callout function.
- @result A dns_registration_t
-*/
-dns_service_discovery_ref DNSServiceBrowserCreate
-(
- const char *regtype,
- const char *domain,
- DNSServiceBrowserReply callBack,
- void *context
-);
-
-/***************************************************************************/
-/* Resolver requests */
-
-typedef void (*DNSServiceResolverReply) (
- struct sockaddr *interfaceAddr, // Needed for scoped addresses like link-local
- struct sockaddr *address,
- const char *txtRecord,
- DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
- void *context
-);
-
-/*!
-@function DNSServiceResolverResolve
- @description Resolved a named instance of a service to its address, port, and
- (optionally) other demultiplexing information contained in the TXT record.
- @param name The name of the service instance
- @param regtype The type of service
- @param domain The domain in which to find the service
- @param callBack The DNSServiceResolverReply function to be called when the specified
- address has been resolved.
- @param context A user specified context which will be passed to the callout function.
- @result A dns_registration_t
-*/
-
-dns_service_discovery_ref DNSServiceResolverResolve
-(
- const char *name,
- const char *regtype,
- const char *domain,
- DNSServiceResolverReply callBack,
- void *context
-);
-
-/***************************************************************************/
-/* Mach port accessor and deallocation */
-
-/*!
- @function DNSServiceDiscoveryMachPort
- @description Returns the mach port for a dns_service_discovery_ref
- @param registration A dns_service_discovery_ref as returned from DNSServiceRegistrationCreate
- @result A mach reply port which will be sent messages as appropriate.
- These messages should be passed to the DNSServiceDiscovery_handleReply
- function. A NULL value indicates that no address was
- specified or some other error occurred which prevented the
- resolution from being started.
-*/
-mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery);
-
-/*!
- @function DNSServiceDiscoveryDeallocate
- @description Deallocates the DNS Service Discovery type / closes the connection to the server
- @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a creation or enumeration call
- @result void
-*/
-void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery);
-
-/***************************************************************************/
-/* Registration updating */
-
-
-/*!
- @function DNSServiceRegistrationAddRecord
- @description Request that the mDNS Responder add the DNS Record of a specific type
- @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
- @param rrtype A standard DNS Resource Record Type, from http://www.iana.org/assignments/dns-parameters
- @param rdlen Length of the data
- @param rdata Opaque binary Resource Record data, up to 64 kB.
- @param ttl time to live for the added record.
- @result DNSRecordReference An opaque reference that can be passed to the update and remove record calls. If an error occurs, this value will be zero or negative
-*/
-DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl);
-
-/*!
- @function DNSServiceRegistrationUpdateRecord
- @description Request that the mDNS Responder add the DNS Record of a specific type
- @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
- @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
- @param rdlen Length of the data
- @param rdata Opaque binary Resource Record data, up to 64 kB.
- @param ttl time to live for the updated record.
- @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
-*/
-DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl);
-
-/*!
- @function DNSServiceRegistrationRemoveRecord
- @description Request that the mDNS Responder remove the DNS Record(s) of a specific type
- @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
- @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
- @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
-*/
-
-DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference);
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif // __DNS_SERVICE_DISCOVERY__
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: DNSServices.c,v $
-Revision 1.32 2004/12/16 20:13:02 cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.31 2004/10/19 21:33:23 cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.30 2004/09/17 01:08:58 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.29 2004/09/17 00:31:53 cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.28 2004/09/16 01:58:25 cheshire
-Fix compiler warnings
-
-Revision 1.27 2004/07/13 21:24:28 rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.26 2004/06/05 00:04:27 cheshire
-<rdar://problem/3668639>: wide-area domains should be returned in reg. domain enumeration
-
-Revision 1.25 2004/04/08 09:31:17 bradley
-Renamed local variable to avoid hiding a system global in some libraries.
-
-Revision 1.24 2004/01/30 02:56:34 bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.23 2004/01/24 23:57:29 cheshire
-Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
-
-Revision 1.22 2003/12/17 21:12:15 bradley
-<rdar://problem/3491823>: Use the default .local domain when registering with an empty domain.
-
-Revision 1.21 2003/11/20 22:29:56 cheshire
-Don't need to use MAX_ESCAPED_DOMAIN_LABEL for the name part -- that's not escaped
-
-Revision 1.20 2003/11/14 21:27:09 cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
-
-Revision 1.19 2003/11/14 20:59:10 cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.18 2003/11/14 19:18:34 cheshire
-Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too
-
-Revision 1.17 2003/10/31 12:16:03 bradley
-Added support for providing the resolved host name to the callback.
-
-Revision 1.16 2003/10/16 09:16:39 bradley
-Unified address copying to fix a problem with IPv6 resolves not being passed up as IPv6.
-
-Revision 1.15 2003/08/20 06:44:24 bradley
-Updated to latest internal version of the mDNSCore code: Added support for interface
-specific registrations; Added support for no-such-service registrations; Added support for host
-name registrations; Added support for host proxy and service proxy registrations; Added support for
-registration record updates (e.g. TXT record updates); Added support for using either a single C
-string TXT record, a raw, pre-formatted TXT record potentially containing multiple character string
-entries, or a C-string containing a Mac OS X-style \001-delimited set of TXT record character
-strings; Added support in resolve callbacks for providing both a simplified C-string for TXT records
-and a ptr/size for the raw TXT record data; Added utility routines for dynamically building TXT
-records from a variety of sources (\001-delimited, individual strings, etc.) and converting TXT
-records to various formats for use in apps; Added utility routines to validate DNS names, DNS
-service types, and TXT records; Moved to portable address representation unions (byte-stream vs host
-order integer) for consistency, to avoid swapping between host and network byte order, and for IPv6
-support; Removed dependence on modified mDNSCore: define structures and prototypes locally; Added
-support for automatically renaming services on name conflicts; Detect and correct TXT records from
-old versions of mDNS that treated a TXT record as an arbitrary block of data, but prevent other
-malformed TXT records from being accepted; Added many more error codes; Added complete HeaderDoc for
-all constants, structures, typedefs, macros, and functions. Various other minor cleanup and fixes.
-
-Revision 1.14 2003/08/14 02:19:56 cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.13 2003/08/12 19:56:29 cheshire
-Update to APSL 2.0
-
-Revision 1.12 2003/07/23 00:00:04 cheshire
-Add comments
-
-Revision 1.11 2003/07/15 01:55:17 cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
-
-Revision 1.10 2003/07/02 21:20:10 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.9 2003/05/26 03:21:30 cheshire
-Tidy up address structure naming:
-mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.8 2003/05/06 00:00:51 cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.7 2003/03/27 03:30:57 cheshire
-<rdar://problem/3210018> Name conflicts not handled properly, resulting in memory corruption, and eventual crash
-Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback
-Fixes:
-1. Make mDNS_DeregisterInterface() safe to call from a callback
-2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead
- (it never really needed to deregister the interface at all)
-
-Revision 1.6 2003/03/22 02:57:45 cheshire
-Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.5 2003/02/20 00:59:04 cheshire
-Brought Windows code up to date so it complies with
-Josh Graessley's interface changes for IPv6 support.
-(Actual support for IPv6 on Windows will come later.)
-
-Revision 1.4 2002/09/21 20:44:56 zarzycki
-Added APSL info
-
-Revision 1.3 2002/09/20 08:36:50 bradley
-Fixed debug messages to output the correct information when resolving.
-
-Revision 1.2 2002/09/20 05:58:01 bradley
-DNS Services for Windows
-
-*/
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if( __MACH__ )
- #include <CoreServices/CoreServices.h>
-#endif
-
-#include "mDNSEmbeddedAPI.h"
-
-#include "DNSServices.h"
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#if 0
-#pragma mark == Preprocessor ==
-#endif
-
-//===========================================================================================================================
-// Preprocessor
-//===========================================================================================================================
-
-#if( defined( _MSC_VER ) )
- #pragma warning( disable:4068 ) // Disable "unknown pragma" warning for "pragma unused".
- #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#define DEBUG_NAME "[DNSServices] "
-
-enum
-{
- kDNSInitializeValidFlags = kDNSFlagAdvertise,
-
- // Browser
-
- kDNSBrowserCreateValidFlags = 0,
- kDNSBrowserReleaseValidFlags = 0,
- kDNSBrowserStartDomainSearchValidFlags = kDNSBrowserFlagRegistrationDomainsOnly,
- kDNSBrowserStopDomainSearchValidFlags = 0,
- kDNSBrowserStartServiceSearchValidFlags = kDNSBrowserFlagAutoResolve,
- kDNSBrowserStopServiceSearchValidFlags = 0,
-
- // Resolver
-
- kDNSResolverCreateValidFlags = kDNSResolverFlagOneShot |
- kDNSResolverFlagOnlyIfUnique |
- kDNSResolverFlagAutoReleaseByName,
- kDNSResolverReleaseValidFlags = 0,
-
- // Service Registration
-
- kDNSRegistrationCreateValidFlags = kDNSRegistrationFlagPreFormattedTextRecord |
- kDNSRegistrationFlagAutoRenameOnConflict,
- kDNSNoSuchServiceRegistrationCreateValidFlags = 0,
- kDNSRegistrationReleaseValidFlags = 0,
- kDNSRegistrationUpdateValidFlags = 0,
-
- kDNSRegistrationFlagPrivateNoSuchService = ( 1 << 16 ),
-
- // Domain Registration
-
- kDNSDomainRegistrationCreateValidFlags = 0,
- kDNSDomainRegistrationReleaseValidFlags = 0,
-
- // Host Registration
-
- kDNSHostRegistrationCreateValidFlags = kDNSHostRegistrationFlagOnlyIfNotFound |
- kDNSHostRegistrationFlagAutoRenameOnConflict,
- kDNSHostRegistrationReleaseValidFlags = 0
-};
-
-#define kDNSCountCacheEntryCountDefault 64
-
-#if 0
-#pragma mark == Structures ==
-#endif
-
-//===========================================================================================================================
-// Structures
-//===========================================================================================================================
-
-// Browser
-
-typedef struct DNSBrowser DNSBrowser;
-struct DNSBrowser
-{
- DNSBrowser * next;
- DNSBrowserFlags flags;
- DNSBrowserCallBack callback;
- void * callbackContext;
- mDNSBool isDomainBrowsing;
- DNSQuestion domainQuestion;
- DNSQuestion defaultDomainQuestion;
- DNSBrowserFlags domainSearchFlags;
- mDNSBool isServiceBrowsing;
- DNSQuestion serviceBrowseQuestion;
- DNSBrowserFlags serviceSearchFlags;
- char searchDomain[ 256 ];
- char searchServiceType[ 256 ];
-};
-
-// Resolver
-
-typedef struct DNSResolver DNSResolver;
-struct DNSResolver
-{
- DNSResolver * next;
- DNSResolverFlags flags;
- DNSResolverCallBack callback;
- void * callbackContext;
- DNSBrowserRef owner;
- ServiceInfoQuery query;
- ServiceInfo info;
- mDNSBool isResolving;
- char resolveName[ 256 ];
- char resolveType[ 256 ];
- char resolveDomain[ 256 ];
-};
-
-// Registration
-
-typedef struct DNSRegistration DNSRegistration;
-struct DNSRegistration
-{
- DNSRegistration * next;
- DNSRegistrationFlags flags;
- DNSRegistrationCallBack callback;
- void * callbackContext;
- char interfaceName[ 256 ];
- ServiceRecordSet set;
-
- // WARNING: Do not add fields after the ServiceRecordSet. This is where oversized TXT record space is allocated.
-};
-
-// Domain Registration
-
-typedef struct DNSDomainRegistration DNSDomainRegistration;
-struct DNSDomainRegistration
-{
- DNSDomainRegistration * next;
- DNSDomainRegistrationFlags flags;
- AuthRecord rr;
-};
-
-// Domain Registration
-
-typedef struct DNSHostRegistration DNSHostRegistration;
-struct DNSHostRegistration
-{
- DNSHostRegistration * next;
- domainlabel name;
- domainlabel domain;
- long refCount;
- DNSHostRegistrationCallBack callback;
- void * callbackContext;
- DNSHostRegistrationFlags flags;
- char interfaceName[ 256 ];
- AuthRecord RR_A;
- AuthRecord RR_PTR;
-};
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//===========================================================================================================================
-// Macros
-//===========================================================================================================================
-
-// Emulate Mac OS debugging macros for non-Mac platforms.
-
-#if( !TARGET_OS_MAC )
- #define check(assertion)
- #define check_string( assertion, cstring )
- #define check_noerr(err)
- #define check_noerr_string( error, cstring )
- #define debug_string( cstring )
- #define require( assertion, label ) do { if( !(assertion) ) goto label; } while(0)
- #define require_string( assertion, label, string ) require(assertion, label)
- #define require_noerr( error, label ) do { if( (error) != 0 ) goto label; } while(0)
- #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
- #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
- #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
-#endif
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-// General
-
-mDNSlocal void DNSServicesLock( void );
-mDNSlocal void DNSServicesUnlock( void );
-mDNSlocal void DNSServicesMDNSCallBack( mDNS *const inMDNS, mStatus inStatus );
-mDNSlocal void DNSServicesUpdateInterfaceSpecificObjects( mDNS *const inMDNS );
-
-// Browser
-
-mDNSlocal void
- DNSBrowserPrivateCallBack(
- mDNS * const inMDNS,
- DNSQuestion * inQuestion,
- const ResourceRecord * const inAnswer,
- mDNSBool inAddRecord );
-
-mDNSlocal void
- DNSBrowserPrivateResolverCallBack(
- void * inContext,
- DNSResolverRef inRef,
- DNSStatus inStatusCode,
- const DNSResolverEvent * inEvent );
-
-mDNSlocal DNSBrowserRef DNSBrowserFindObject( DNSBrowserRef inRef );
-mDNSlocal DNSBrowserRef DNSBrowserRemoveObject( DNSBrowserRef inRef );
-
-// Resolver
-
-mDNSlocal void DNSResolverPrivateCallBack( mDNS * const inMDNS, ServiceInfoQuery *inQuery );
-mDNSlocal DNSResolverRef DNSResolverFindObject( DNSResolverRef inRef );
-mDNSlocal DNSResolverRef DNSResolverRemoveObject( DNSResolverRef inRef );
-mDNSlocal void DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef );
-mDNSlocal void DNSResolverRemoveDependentByName( const domainname *inName );
-mDNSlocal DNSResolverRef DNSResolverFindObjectByName( const domainname *inName );
-
-// Registration
-
-mDNSlocal void
- DNSRegistrationPrivateCallBack(
- mDNS * const inMDNS,
- ServiceRecordSet * const inSet,
- mStatus inResult );
-
-mDNSlocal void
- DNSNoSuchServiceRegistrationPrivateCallBack(
- mDNS * const inMDNS,
- AuthRecord * const inRR,
- mStatus inResult );
-
-mDNSlocal void DNSRegistrationUpdateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldData );
-
-mDNSlocal DNSRegistrationRef * DNSRegistrationFindObject( DNSRegistrationRef inRef );
-mDNSlocal DNSRegistrationRef DNSRegistrationRemoveObject( DNSRegistrationRef inRef );
-
-// Domain Registration
-
-mDNSlocal DNSDomainRegistrationRef DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef );
-
-// Host Registration
-
-mDNSlocal DNSHostRegistrationRef * DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef );
-mDNSlocal DNSHostRegistrationRef DNSHostRegistrationFindObjectByName( const domainname *inName );
-mDNSlocal void DNSHostRegistrationPrivateCallBack( mDNS * const inMDNS, AuthRecord *const inRR, mStatus inResult );
-
-// Utilities
-
-mDNSlocal DNSStatus DNSMemAlloc( size_t inSize, void *outMem );
-mDNSlocal void DNSMemFree( void *inMem );
-mDNSlocal void MDNSAddrToDNSAddress( const mDNSAddr *inAddr, mDNSIPPort inPort, DNSNetworkAddress *outAddr );
-
-// Platform Accessors
-
-typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
-struct mDNSPlatformInterfaceInfo
-{
- const char * name;
- mDNSAddr ip;
-};
-
-mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
-mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-mDNSexport mDNS gMDNS;
-mDNSlocal mDNS * gMDNSPtr = mDNSNULL;
-mDNSlocal CacheRecord * gMDNSCache = mDNSNULL;
-mDNSlocal DNSBrowserRef gDNSBrowserList = mDNSNULL;
-mDNSlocal DNSResolverRef gDNSResolverList = mDNSNULL;
-mDNSlocal DNSRegistrationRef gDNSRegistrationList = mDNSNULL;
-mDNSlocal DNSDomainRegistrationRef gDNSDomainRegistrationList = mDNSNULL;
-mDNSlocal DNSHostRegistrationRef gDNSHostRegistrationList = mDNSNULL;
-
-#if 0
-#pragma mark -
-#pragma mark == General ==
-#endif
-
-//===========================================================================================================================
-// DNSServicesInitialize
-//===========================================================================================================================
-
-DNSStatus DNSServicesInitialize( DNSFlags inFlags, DNSCount inCacheEntryCount )
-{
- DNSStatus err;
- mDNSBool advertise;
-
- require_action( ( inFlags & ~kDNSInitializeValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-
- // Allocate the record cache.
-
- if( inCacheEntryCount == 0 )
- {
- inCacheEntryCount = kDNSCountCacheEntryCountDefault;
- }
- gMDNSCache = (CacheRecord *) malloc( inCacheEntryCount * sizeof( *gMDNSCache ) );
- require_action( gMDNSCache, exit, err = kDNSNoMemoryErr );
-
- // Initialize mDNS.
-
- if( inFlags & kDNSFlagAdvertise )
- {
- advertise = mDNS_Init_AdvertiseLocalAddresses;
- }
- else
- {
- advertise = mDNS_Init_DontAdvertiseLocalAddresses;
- }
- err = mDNS_Init( &gMDNS, mDNSNULL, gMDNSCache, inCacheEntryCount, advertise, DNSServicesMDNSCallBack, mDNSNULL );
- require_noerr( err, exit );
- err = gMDNS.mDNSPlatformStatus;
- require_noerr( err, exit );
-
- gMDNSPtr = &gMDNS;
-
-exit:
- if( err )
- {
- DNSServicesFinalize();
- }
- return( err );
-}
-
-//===========================================================================================================================
-// DNSServicesFinalize
-//===========================================================================================================================
-
-void DNSServicesFinalize( void )
-{
- if( gMDNSPtr )
- {
- mDNSPlatformLock( &gMDNS );
-
- // Clean up any dangling service registrations.
-
- while( gDNSRegistrationList )
- {
- DNSRegistrationRef serviceRef;
-
- serviceRef = gDNSRegistrationList;
- DNSRegistrationRelease( serviceRef, 0UL );
- check_string( serviceRef != gDNSRegistrationList, "dangling service registration cannot be cleaned up" );
- }
-
- // Clean up any dangling domain registrations.
-
- while( gDNSDomainRegistrationList )
- {
- DNSDomainRegistrationRef domainRef;
-
- domainRef = gDNSDomainRegistrationList;
- DNSDomainRegistrationRelease( domainRef, 0 );
- check_string( domainRef != gDNSDomainRegistrationList, "dangling domain registration cannot be cleaned up" );
- }
-
- // Clean up any dangling host registrations.
-
- while( gDNSHostRegistrationList )
- {
- DNSHostRegistrationRef hostRef;
- long refCount;
-
- hostRef = gDNSHostRegistrationList;
- refCount = hostRef->refCount;
- DNSHostRegistrationRelease( hostRef, 0 );
- check_string( ( refCount > 1 ) || ( hostRef != gDNSHostRegistrationList ),
- "dangling host registration cannot be cleaned up" );
- }
-
- // Clean up any dangling browsers.
-
- while( gDNSBrowserList )
- {
- DNSBrowserRef browserRef;
-
- browserRef = gDNSBrowserList;
- DNSBrowserRelease( browserRef, 0 );
- check_string( browserRef != gDNSBrowserList, "dangling browser cannot be cleaned up" );
- }
-
- // Clean up any dangling resolvers.
-
- while( gDNSResolverList )
- {
- DNSResolverRef resolverRef;
-
- resolverRef = gDNSResolverList;
- DNSResolverRelease( resolverRef, 0 );
- check_string( resolverRef != gDNSResolverList, "dangling resolver cannot be cleaned up" );
- }
-
- // Null out our MDNS ptr before releasing the lock so no other threads can sneak in and start operations.
-
- gMDNSPtr = mDNSNULL;
- mDNSPlatformUnlock( &gMDNS );
-
- // Tear down mDNS.
-
- mDNS_Close( &gMDNS );
- }
- if( gMDNSCache )
- {
- free( gMDNSCache );
- gMDNSCache = mDNSNULL;
- }
-}
-
-//===========================================================================================================================
-// DNSServicesLock
-//===========================================================================================================================
-
-mDNSlocal void DNSServicesLock( void )
-{
- if( gMDNSPtr )
- {
- mDNSPlatformLock( gMDNSPtr );
- }
-}
-
-//===========================================================================================================================
-// DNSServicesUnlock
-//===========================================================================================================================
-
-mDNSlocal void DNSServicesUnlock( void )
-{
- if( gMDNSPtr )
- {
- mDNSPlatformUnlock( gMDNSPtr );
- }
-}
-
-//===========================================================================================================================
-// DNSServicesMDNSCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSServicesMDNSCallBack( mDNS *const inMDNS, mStatus inStatus )
-{
- DNS_UNUSED( inMDNS );
- DNS_UNUSED( inStatus );
- check( inMDNS );
-
- debugf( DEBUG_NAME "MDNS callback (status=%ld)", inStatus );
-
- if( inStatus == mStatus_ConfigChanged )
- {
- DNSServicesUpdateInterfaceSpecificObjects( inMDNS );
- }
-}
-
-//===========================================================================================================================
-// DNSServicesUpdateInterfaceSpecificObjects
-//===========================================================================================================================
-
-mDNSlocal void DNSServicesUpdateInterfaceSpecificObjects( mDNS *const inMDNS )
-{
- DNSRegistration * serviceRegistration;
-
- DNSServicesLock();
-
- // Update interface-specific service registrations.
-
- for( serviceRegistration = gDNSRegistrationList; serviceRegistration; serviceRegistration = serviceRegistration->next )
- {
- if( serviceRegistration->interfaceName[ 0 ] != '\0' )
- {
- mStatus err;
- mDNSInterfaceID interfaceID;
-
- err = mDNSPlatformInterfaceNameToID( inMDNS, serviceRegistration->interfaceName, &interfaceID );
- check_noerr( err );
- if( err == mStatus_NoError )
- {
- // Update all the resource records with the new interface ID.
-
- serviceRegistration->set.RR_ADV.resrec.InterfaceID = interfaceID;
- serviceRegistration->set.RR_PTR.resrec.InterfaceID = interfaceID;
- serviceRegistration->set.RR_SRV.resrec.InterfaceID = interfaceID;
- serviceRegistration->set.RR_TXT.resrec.InterfaceID = interfaceID;
- }
- }
- }
-
- DNSServicesUnlock();
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Browser ==
-#endif
-
-//===========================================================================================================================
-// DNSBrowserCreate
-//===========================================================================================================================
-
-DNSStatus
- DNSBrowserCreate(
- DNSBrowserFlags inFlags,
- DNSBrowserCallBack inCallBack,
- void * inCallBackContext,
- DNSBrowserRef * outRef )
-{
- DNSStatus err;
- DNSBrowser * objectPtr;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( ( inFlags & ~kDNSBrowserCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- require_action( inCallBack, exit, err = kDNSBadParamErr );
-
- // Allocate the object and set it up.
-
- err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
- require_noerr( err, exit );
- memset( objectPtr, 0, sizeof( *objectPtr ) );
-
- objectPtr->flags = inFlags;
- objectPtr->callback = inCallBack;
- objectPtr->callbackContext = inCallBackContext;
-
- // Add the object to the list.
-
- objectPtr->next = gDNSBrowserList;
- gDNSBrowserList = objectPtr;
-
- if( outRef )
- {
- *outRef = objectPtr;
- }
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSBrowserRelease
-//===========================================================================================================================
-
-DNSStatus DNSBrowserRelease( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
-{
- DNSStatus err;
- DNSBrowserEvent event;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( inRef, exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSBrowserReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-
- // Stop service and domain browsing and remove any resolvers dependent on this browser.
-
- DNSBrowserStopDomainSearch( inRef, 0 );
- DNSBrowserStopServiceSearch( inRef, 0 );
- DNSResolverRemoveDependentByBrowser( inRef );
-
- // Remove the object from the list.
-
- inRef = DNSBrowserRemoveObject( inRef );
- require_action( inRef, exit, err = kDNSBadReferenceErr );
-
- // Call the callback with a release event.
-
- check( inRef->callback );
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSBrowserEventTypeRelease;
- inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
-
- // Release the memory used by the object.
-
- DNSMemFree( inRef );
- err = kDNSNoErr;
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSBrowserStartDomainSearch
-//===========================================================================================================================
-
-DNSStatus DNSBrowserStartDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
-{
- DNSStatus err;
- mDNS_DomainType type;
- mDNS_DomainType defaultType;
- DNSBrowserEvent event;
- mDNSBool isDomainBrowsing;
-
- isDomainBrowsing = mDNSfalse;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( inRef && DNSBrowserFindObject( inRef ), exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSBrowserStartDomainSearchValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- require_action( !inRef->isDomainBrowsing, exit, err = kDNSBadStateErr );
-
- // Determine whether to browse for normal domains or registration domains.
-
- if( inFlags & kDNSBrowserFlagRegistrationDomainsOnly )
- {
- type = mDNS_DomainTypeRegistration;
- defaultType = mDNS_DomainTypeRegistrationDefault;
- }
- else
- {
- type = mDNS_DomainTypeBrowse;
- defaultType = mDNS_DomainTypeBrowseDefault;
- }
-
- // Start the browse operations.
-
- err = mDNS_GetDomains( gMDNSPtr, &inRef->domainQuestion, type, NULL, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
- require_noerr( err, exit );
- isDomainBrowsing = mDNStrue;
-
- err = mDNS_GetDomains( gMDNSPtr, &inRef->defaultDomainQuestion, defaultType, NULL, mDNSInterface_Any, DNSBrowserPrivateCallBack, inRef );
- require_noerr( err, exit );
-
- inRef->domainSearchFlags = inFlags;
- inRef->isDomainBrowsing = mDNStrue;
-
- // Call back immediately with "local." since that is always available for all types of browsing.
-
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSBrowserEventTypeAddDefaultDomain;
- event.data.addDefaultDomain.domain = kDNSLocalDomain;
- event.data.addDefaultDomain.flags = 0;
- inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
-
-exit:
- if( err && isDomainBrowsing )
- {
- mDNS_StopGetDomains( gMDNSPtr, &inRef->domainQuestion );
- }
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSBrowserStopDomainSearch
-//===========================================================================================================================
-
-DNSStatus DNSBrowserStopDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
-{
- DNSStatus err;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( inRef && DNSBrowserFindObject( inRef ), exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSBrowserStopDomainSearchValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- if( !inRef->isDomainBrowsing )
- {
- err = kDNSBadStateErr;
- goto exit;
- }
-
- // Stop the browse operations.
-
- mDNS_StopGetDomains( gMDNSPtr, &inRef->defaultDomainQuestion );
- mDNS_StopGetDomains( gMDNSPtr, &inRef->domainQuestion );
- inRef->isDomainBrowsing = mDNSfalse;
- err = kDNSNoErr;
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSBrowserStartServiceSearch
-//===========================================================================================================================
-
-DNSStatus
- DNSBrowserStartServiceSearch(
- DNSBrowserRef inRef,
- DNSBrowserFlags inFlags,
- const char * inType,
- const char * inDomain )
-{
- DNSStatus err;
- domainname type;
- domainname domain;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( inRef && DNSBrowserFindObject( inRef ), exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSBrowserStartServiceSearchValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- require_action( !inRef->isServiceBrowsing, exit, err = kDNSBadStateErr );
- require_action( inType, exit, err = kDNSBadParamErr );
-
- // Default to the local domain when a NULL, empty, or "." domain is passed in.
-
- if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
- {
- inDomain = kDNSLocalDomain;
- }
-
- // Save off the search criteria (in case it needs to be automatically restarted later).
-
- inRef->serviceSearchFlags = inFlags;
-
- strncpy( inRef->searchServiceType, inType, sizeof( inRef->searchServiceType ) - 1 );
- inRef->searchServiceType[ sizeof( inRef->searchServiceType ) - 1 ] = '\0';
-
- strncpy( inRef->searchDomain, inDomain, sizeof( inRef->searchDomain ) - 1 );
- inRef->searchDomain[ sizeof( inRef->searchDomain ) - 1 ] = '\0';
-
- // Start the browse operation with mDNS using our private callback.
-
- MakeDomainNameFromDNSNameString( &type, inType );
- MakeDomainNameFromDNSNameString( &domain, inDomain );
-
- err = mDNS_StartBrowse( gMDNSPtr, &inRef->serviceBrowseQuestion, &type, &domain, mDNSInterface_Any, mDNSfalse,
- DNSBrowserPrivateCallBack, inRef );
- require_noerr( err, exit );
-
- inRef->isServiceBrowsing = mDNStrue;
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSBrowserStopServiceSearch
-//===========================================================================================================================
-
-DNSStatus DNSBrowserStopServiceSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags )
-{
- DNSStatus err;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( inRef && DNSBrowserFindObject( inRef ), exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSBrowserStopServiceSearchValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- if( !inRef->isServiceBrowsing )
- {
- err = kDNSBadStateErr;
- goto exit;
- }
-
- // Stop the browse operation with mDNS. Remove any resolvers dependent on browser since we are no longer searching.
-
- mDNS_StopBrowse( gMDNSPtr, &inRef->serviceBrowseQuestion );
- DNSResolverRemoveDependentByBrowser( inRef );
- inRef->isServiceBrowsing = mDNSfalse;
- err = kDNSNoErr;
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSBrowserPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void
- DNSBrowserPrivateCallBack(
- mDNS * const inMDNS,
- DNSQuestion * inQuestion,
- const ResourceRecord * const inAnswer,
- mDNSBool inAddRecord )
-{
- DNSBrowserRef objectPtr;
- domainlabel name;
- domainname type;
- domainname domain;
- char nameString [ MAX_DOMAIN_LABEL + 1 ]; // Name part is not escaped
- char typeString [ MAX_ESCAPED_DOMAIN_NAME ];
- char domainString[ MAX_ESCAPED_DOMAIN_NAME ];
- DNSBrowserEvent event;
- mStatus err;
-
- check( inMDNS );
- check( inQuestion );
- check( inAnswer );
-
- DNSServicesLock();
-
- // Exclude non-PTR answers.
-
- require( inAnswer->rrtype == kDNSType_PTR, exit );
-
- // Exit if object is no longer valid. Should never happen.
-
- objectPtr = DNSBrowserFindObject( (DNSBrowserRef) inQuestion->QuestionContext );
- require( objectPtr, exit );
-
- // Determine what type of callback it is based on the question.
-
- memset( &event, 0, sizeof( event ) );
- if( inQuestion == &objectPtr->serviceBrowseQuestion )
- {
- DNSBrowserEventServiceData * serviceDataPtr;
- DNSBrowserFlags browserFlags;
-
- // Extract name, type, and domain from the resource record.
-
- DeconstructServiceName( &inAnswer->rdata->u.name, &name, &type, &domain );
- ConvertDomainLabelToCString_unescaped( &name, nameString );
- ConvertDomainNameToCString( &type, typeString );
- ConvertDomainNameToCString( &domain, domainString );
-
- // Fill in the event data. A TTL of zero means the service is no longer available. If the service instance is going
- // away (ttl == 0), remove any resolvers dependent on the name since it is no longer valid.
-
- if( !inAddRecord )
- {
- DNSResolverRemoveDependentByName( &inAnswer->rdata->u.name );
-
- event.type = kDNSBrowserEventTypeRemoveService;
- serviceDataPtr = &event.data.removeService;
- }
- else
- {
- event.type = kDNSBrowserEventTypeAddService;
- serviceDataPtr = &event.data.addService;
- }
- serviceDataPtr->interfaceName = "";
- if( inAnswer->InterfaceID != mDNSInterface_Any )
- {
- mDNSPlatformInterfaceInfo info;
-
- err = mDNSPlatformInterfaceIDToInfo( inMDNS, inAnswer->InterfaceID, &info );
- if( err == mStatus_NoError )
- {
- serviceDataPtr->interfaceName = info.name;
- MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &serviceDataPtr->interfaceIP );
- }
- else
- {
- serviceDataPtr->interfaceName = "";
- }
- }
- serviceDataPtr->interfaceID = inAnswer->InterfaceID;
- serviceDataPtr->name = nameString;
- serviceDataPtr->type = typeString;
- serviceDataPtr->domain = domainString;
- serviceDataPtr->flags = 0;
-
- // Call the callback.
-
- browserFlags = objectPtr->serviceSearchFlags;
- objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
-
- // Automatically resolve newly discovered names if the auto-resolve option is enabled.
-
- if( ( browserFlags & kDNSBrowserFlagAutoResolve ) && inAddRecord )
- {
- DNSResolverFlags flags;
-
- flags = kDNSResolverFlagOnlyIfUnique | kDNSResolverFlagAutoReleaseByName;
- err = DNSResolverCreate( flags, nameString, typeString, domainString, DNSBrowserPrivateResolverCallBack,
- mDNSNULL, objectPtr, mDNSNULL );
- check_noerr( err );
- }
- }
- else
- {
- DNSBrowserEventDomainData * domainDataPtr;
-
- // Determine the event type. A TTL of zero means the domain is no longer available.
-
- domainDataPtr = mDNSNULL;
- if( inQuestion == &objectPtr->domainQuestion )
- {
- if( !inAddRecord )
- {
- event.type = kDNSBrowserEventTypeRemoveDomain;
- domainDataPtr = &event.data.removeDomain;
- }
- else
- {
- event.type = kDNSBrowserEventTypeAddDomain;
- domainDataPtr = &event.data.addDomain;
- }
- }
- else if( inQuestion == &objectPtr->defaultDomainQuestion )
- {
- if( !inAddRecord )
- {
- event.type = kDNSBrowserEventTypeRemoveDomain;
- domainDataPtr = &event.data.removeDomain;
- }
- else
- {
- event.type = kDNSBrowserEventTypeAddDefaultDomain;
- domainDataPtr = &event.data.addDefaultDomain;
- }
- }
- require_string( domainDataPtr, exit, "domain response for unknown question" );
-
- // Extract domain name from the resource record and fill in the event data.
-
- ConvertDomainNameToCString( &inAnswer->rdata->u.name, domainString );
-
- domainDataPtr->interfaceName = "";
- if( inAnswer->InterfaceID != mDNSInterface_Any )
- {
- mDNSPlatformInterfaceInfo info;
-
- err = mDNSPlatformInterfaceIDToInfo( inMDNS, inAnswer->InterfaceID, &info );
- if( err == mStatus_NoError )
- {
- domainDataPtr->interfaceName = info.name;
- MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &domainDataPtr->interfaceIP );
- }
- else
- {
- domainDataPtr->interfaceName = "";
- }
- }
- domainDataPtr->interfaceID = inAnswer->InterfaceID;
- domainDataPtr->domain = domainString;
- domainDataPtr->flags = 0;
-
- // Call the callback.
-
- objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
- }
-
-exit:
- DNSServicesUnlock();
-}
-
-//===========================================================================================================================
-// DNSBrowserPrivateResolverCallBack
-//===========================================================================================================================
-
-mDNSlocal void
- DNSBrowserPrivateResolverCallBack(
- void * inContext,
- DNSResolverRef inRef,
- DNSStatus inStatusCode,
- const DNSResolverEvent * inEvent )
-{
- DNSBrowserRef objectPtr;
- DNSBrowserEvent event;
-
- DNS_UNUSED( inContext );
- DNS_UNUSED( inStatusCode );
-
- DNSServicesLock();
-
- // Exit if object is no longer valid. Should never happen.
-
- objectPtr = inRef->owner;
- require( objectPtr, exit );
-
- switch( inEvent->type )
- {
- case kDNSResolverEventTypeResolved:
-
- // Re-package the resolver event as a browser event and call the callback.
-
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSBrowserEventTypeResolved;
- event.data.resolved = &inEvent->data.resolved;
-
- objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
- break;
-
- case kDNSResolverEventTypeRelease:
- verbosedebugf( DEBUG_NAME "private resolver callback: release (ref=0x%p)", inRef );
- break;
-
- default:
- verbosedebugf( DEBUG_NAME "private resolver callback: unknown event (ref=0x%p, event=%ld)", inRef, inEvent->type );
- break;
- }
-
-exit:
- DNSServicesUnlock();
-}
-
-//===========================================================================================================================
-// DNSBrowserFindObject
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSBrowserRef DNSBrowserFindObject( DNSBrowserRef inRef )
-{
- DNSBrowser * p;
-
- check( inRef );
-
- // Find the object in the list.
-
- for( p = gDNSBrowserList; p; p = p->next )
- {
- if( p == inRef )
- {
- break;
- }
- }
- return( p );
-}
-
-//===========================================================================================================================
-// DNSBrowserRemoveObject
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSBrowserRef DNSBrowserRemoveObject( DNSBrowserRef inRef )
-{
- DNSBrowser ** p;
- DNSBrowser * found;
-
- for( p = &gDNSBrowserList; *p; p = &( *p )->next )
- {
- if( *p == inRef )
- {
- break;
- }
- }
- found = *p;
- if( found )
- {
- *p = found->next;
- }
- return( found );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Resolver ==
-#endif
-
-//===========================================================================================================================
-// DNSResolverCreate
-//===========================================================================================================================
-
-DNSStatus
- DNSResolverCreate(
- DNSResolverFlags inFlags,
- const char * inName,
- const char * inType,
- const char * inDomain,
- DNSResolverCallBack inCallBack,
- void * inCallBackContext,
- DNSBrowserRef inOwner,
- DNSResolverRef * outRef )
-{
- DNSStatus err;
- int isAutoRelease;
- DNSResolver * objectPtr;
- domainlabel name;
- domainname type;
- domainname domain;
- domainname fullName;
-
- objectPtr = mDNSNULL;
-
- // Check parameters.
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( ( inFlags & ~kDNSResolverCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- require_action( inName, exit, err = kDNSBadParamErr );
- require_action( inType, exit, err = kDNSBadParamErr );
- require_action( inDomain, exit, err = kDNSBadParamErr );
- require_action( inCallBack, exit, err = kDNSBadParamErr );
- isAutoRelease = inOwner || ( inFlags & ( kDNSResolverFlagOneShot | kDNSResolverFlagAutoReleaseByName ) );
- require_action( outRef || isAutoRelease, exit, err = kDNSBadParamErr );
- require_action( !inOwner || DNSBrowserFindObject( inOwner ), exit, err = kDNSBadReferenceErr );
-
- // Convert and package up the name, type, and domain into a single fully-qualified domain name to resolve.
-
- MakeDomainLabelFromLiteralString( &name, inName );
- MakeDomainNameFromDNSNameString( &type, inType );
- MakeDomainNameFromDNSNameString( &domain, inDomain );
- ConstructServiceName( &fullName, &name, &type, &domain );
-
- // If the caller only wants to add unique resolvers, check if a resolver for this name is already present.
-
- if( inFlags & kDNSResolverFlagOnlyIfUnique )
- {
- if( DNSResolverFindObjectByName( &fullName ) )
- {
- if( outRef )
- {
- *outRef = mDNSNULL;
- }
- err = kDNSNoErr;
- goto exit;
- }
- }
-
- // Allocate the object and set it up.
-
- err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
- require_noerr( err, exit );
- memset( objectPtr, 0, sizeof( *objectPtr ) );
-
- objectPtr->flags = inFlags;
- objectPtr->callback = inCallBack;
- objectPtr->callbackContext = inCallBackContext;
- objectPtr->owner = inOwner;
- AssignDomainName( &objectPtr->info.name, &fullName );
- objectPtr->info.InterfaceID = mDNSInterface_Any;
-
- // Save off the resolve info so the callback can get it.
-
- strncpy( objectPtr->resolveName, inName, sizeof( objectPtr->resolveName ) - 1 );
- objectPtr->resolveName[ sizeof( objectPtr->resolveName ) - 1 ] = '\0';
-
- strncpy( objectPtr->resolveType, inType, sizeof( objectPtr->resolveType ) - 1 );
- objectPtr->resolveType[ sizeof( objectPtr->resolveType ) - 1 ] = '\0';
-
- strncpy( objectPtr->resolveDomain, inDomain, sizeof( objectPtr->resolveDomain ) - 1 );
- objectPtr->resolveDomain[ sizeof( objectPtr->resolveDomain ) - 1 ] = '\0';
-
- // Add the object to the list.
-
- objectPtr->next = gDNSResolverList;
- gDNSResolverList = objectPtr;
-
- // Start the resolving process.
-
- objectPtr->isResolving = mDNStrue;
- err = mDNS_StartResolveService( gMDNSPtr, &objectPtr->query, &objectPtr->info, DNSResolverPrivateCallBack, objectPtr );
- require_noerr( err, exit );
-
- if( outRef )
- {
- *outRef = objectPtr;
- }
-
-exit:
- if( err && objectPtr )
- {
- DNSResolverRemoveObject( objectPtr );
- DNSMemFree( objectPtr );
- }
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSResolverRelease
-//===========================================================================================================================
-
-DNSStatus DNSResolverRelease( DNSResolverRef inRef, DNSResolverFlags inFlags )
-{
- DNSStatus err;
- DNSResolverEvent event;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( ( inFlags & ~kDNSResolverReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-
- // Remove the object from the list.
-
- inRef = DNSResolverRemoveObject( inRef );
- require_action( inRef, exit, err = kDNSBadReferenceErr );
-
- // Stop the resolving process.
-
- if( inRef->isResolving )
- {
- inRef->isResolving = mDNSfalse;
- mDNS_StopResolveService( gMDNSPtr, &inRef->query );
- }
-
- // Call the callback with a release event.
-
- check( inRef->callback );
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSResolverEventTypeRelease;
- inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
-
- // Release the memory used by the object.
-
- DNSMemFree( inRef );
- err = kDNSNoErr;
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSResolverFindObject
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSResolverRef DNSResolverFindObject( DNSResolverRef inRef )
-{
- DNSResolver * p;
-
- check( inRef );
-
- // Find the object in the list.
-
- for( p = gDNSResolverList; p; p = p->next )
- {
- if( p == inRef )
- {
- break;
- }
- }
- return( p );
-}
-
-//===========================================================================================================================
-// DNSResolverFindObjectByName
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSResolverRef DNSResolverFindObjectByName( const domainname *inName )
-{
- DNSResolver * p;
-
- check( inName );
-
- for( p = gDNSResolverList; p; p = p->next )
- {
- if( SameDomainName( &p->info.name, inName ) )
- {
- break;
- }
- }
- return( p );
-}
-
-//===========================================================================================================================
-// DNSResolverPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSResolverPrivateCallBack( mDNS * const inMDNS, ServiceInfoQuery *inQuery )
-{
- DNSResolverRef objectPtr;
- DNSResolverEvent event;
- char * txtString;
- mStatus err;
- mDNSBool release;
- char hostName[ MAX_ESCAPED_DOMAIN_NAME ];
-
- txtString = NULL;
-
- DNSServicesLock();
-
- // Exit if object is no longer valid. Should never happen.
-
- objectPtr = DNSResolverFindObject( (DNSResolverRef) inQuery->ServiceInfoQueryContext );
- require( objectPtr, exit );
-
- // Convert the raw TXT record into a null-terminated string with \001-delimited records for Mac OS X-style clients.
-
- err = DNSTextRecordEscape( inQuery->info->TXTinfo, inQuery->info->TXTlen, &txtString );
- check_noerr( err );
-
- // Package up the results and call the callback.
-
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSResolverEventTypeResolved;
- event.data.resolved.name = objectPtr->resolveName;
- event.data.resolved.type = objectPtr->resolveType;
- event.data.resolved.domain = objectPtr->resolveDomain;
- event.data.resolved.interfaceName = "";
- if( inQuery->info->InterfaceID != mDNSInterface_Any )
- {
- mDNSPlatformInterfaceInfo info;
-
- err = mDNSPlatformInterfaceIDToInfo( inMDNS, inQuery->info->InterfaceID, &info );
- if( err == mStatus_NoError )
- {
- event.data.resolved.interfaceName = info.name;
- MDNSAddrToDNSAddress( &info.ip, zeroIPPort, &event.data.resolved.interfaceIP );
- }
- else
- {
- event.data.resolved.interfaceName = "";
- }
- }
- event.data.resolved.interfaceID = inQuery->info->InterfaceID;
- MDNSAddrToDNSAddress( &inQuery->info->ip, inQuery->info->port, &event.data.resolved.address );
- event.data.resolved.textRecord = txtString ? txtString : "";
- event.data.resolved.flags = 0;
- event.data.resolved.textRecordRaw = (const void *) inQuery->info->TXTinfo;
- event.data.resolved.textRecordRawSize = (DNSCount) inQuery->info->TXTlen;
- ConvertDomainNameToCString( &inQuery->qAv4.qname, hostName );
- event.data.resolved.hostName = hostName;
- release = (mDNSBool)( ( objectPtr->flags & kDNSResolverFlagOneShot ) != 0 );
- objectPtr->callback( objectPtr->callbackContext, objectPtr, kDNSNoErr, &event );
-
- // Auto-release the object if needed.
-
- if( release )
- {
- DNSResolverRelease( objectPtr, 0 );
- }
-
-exit:
- DNSServicesUnlock();
- if( txtString )
- {
- free( txtString );
- }
-}
-
-//===========================================================================================================================
-// DNSResolverRemoveObject
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSResolverRef DNSResolverRemoveObject( DNSResolverRef inRef )
-{
- DNSResolver ** p;
- DNSResolver * found;
-
- for( p = &gDNSResolverList; *p; p = &( *p )->next )
- {
- if( *p == inRef )
- {
- break;
- }
- }
- found = *p;
- if( found )
- {
- *p = found->next;
- }
- return( found );
-}
-
-//===========================================================================================================================
-// DNSResolverRemoveDependentByBrowser
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal void DNSResolverRemoveDependentByBrowser( DNSBrowserRef inBrowserRef )
-{
- DNSResolver * p;
-
- check( inBrowserRef );
-
- // Removes all the resolver objects dependent on the specified browser. Restart the search from the beginning of the
- // list after each removal to handle the list changing in possible callbacks that may be invoked.
-
- do
- {
- for( p = gDNSResolverList; p; p = p->next )
- {
- if( p->owner == inBrowserRef )
- {
- DNSResolverRelease( p, 0 );
- break;
- }
- }
-
- } while( p );
-}
-
-//===========================================================================================================================
-// DNSResolverRemoveDependentByName
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal void DNSResolverRemoveDependentByName( const domainname *inName )
-{
- DNSResolver * p;
-
- check( inName );
-
- // Removes all the resolver objects dependent on the specified name that want to be auto-released by name. Restart
- // the search from the beginning of the list after each removal to handle the list changing in possible callbacks
- // that may be invoked.
-
- do
- {
- for( p = gDNSResolverList; p; p = p->next )
- {
- if( ( p->flags & kDNSResolverFlagAutoReleaseByName ) && SameDomainName( &p->info.name, inName ) )
- {
- DNSResolverRelease( p, 0 );
- break;
- }
- }
-
- } while( p );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Registration ==
-#endif
-
-//===========================================================================================================================
-// DNSRegistrationCreate
-//===========================================================================================================================
-
-DNSStatus
- DNSRegistrationCreate(
- DNSRegistrationFlags inFlags,
- const char * inName,
- const char * inType,
- const char * inDomain,
- DNSPort inPort,
- const void * inTextRecord,
- DNSCount inTextRecordSize,
- const char * inHost,
- const char * inInterfaceName,
- DNSRegistrationCallBack inCallBack,
- void * inCallBackContext,
- DNSRegistrationRef * outRef )
-{
- DNSStatus err;
- size_t size;
- DNSRegistration * objectPtr;
- mDNSInterfaceID interfaceID;
- domainlabel name;
- domainname type;
- domainname domain;
- mDNSu8 textRecord[ 256 ];
- const mDNSu8 * textRecordPtr;
- domainname * host;
- domainname tempHost;
-
- objectPtr = mDNSNULL;
-
- // Check parameters.
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( ( inFlags & ~kDNSRegistrationCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- require_action( inType, exit, err = kDNSBadParamErr );
- require_action( inTextRecord || ( inTextRecordSize == 0 ), exit, err = kDNSBadParamErr );
- require_action( ( inFlags & kDNSRegistrationFlagPreFormattedTextRecord ) ||
- ( inTextRecordSize < sizeof( textRecord ) ), exit, err = kDNSBadParamErr );
- require_action( !inInterfaceName ||
- ( strlen( inInterfaceName ) < sizeof( objectPtr->interfaceName ) ), exit, err = kDNSBadParamErr );
-
- // Default to the local domain when a NULL, empty, or "." domain is passed in.
-
- if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
- {
- inDomain = kDNSLocalDomain;
- }
-
- // Set up the text record. If the pre-formatted flag is used, the input text is assumed to be a valid text record
- // and is used directly. Otherwise, the input text is assumed to be raw text and is converted to a text record.
-
- textRecordPtr = (const mDNSu8 *) inTextRecord;
- if( !( inFlags & kDNSRegistrationFlagPreFormattedTextRecord ) )
- {
- // Convert the raw input text to a length-prefixed text record.
-
- if( inTextRecordSize > 0 )
- {
- textRecord[ 0 ] = (mDNSu8) inTextRecordSize;
- memcpy( &textRecord[ 1 ], inTextRecord, inTextRecordSize );
- textRecordPtr = textRecord;
- inTextRecordSize += 1;
- }
- }
-
- // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
-
- size = sizeof( *objectPtr );
- if( inTextRecordSize > sizeof( RDataBody ) )
- {
- size += ( inTextRecordSize - sizeof( RDataBody ) );
- }
-
- err = DNSMemAlloc( size, &objectPtr );
- require_noerr( err, exit );
- memset( objectPtr, 0, size );
-
- objectPtr->flags = inFlags;
- objectPtr->callback = inCallBack;
- objectPtr->callbackContext = inCallBackContext;
-
- // Set up the interface for interface-specific operations.
-
- if( inInterfaceName && ( *inInterfaceName != '\0' ) )
- {
- strcpy( objectPtr->interfaceName, inInterfaceName );
-
- err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
- require_noerr( err, exit );
- }
- else
- {
- interfaceID = mDNSInterface_Any;
- }
-
- // Add the object to the list.
-
- objectPtr->next = gDNSRegistrationList;
- gDNSRegistrationList = objectPtr;
-
- // Convert the name, type, domain, and port to a format suitable for mDNS. If the name is NULL or an empty string,
- // use the UTF-8 name of the system as the service name to make it easy for clients to use the standard name.
- // If we're using the system name (i.e. name is NULL), automatically rename on conflicts to keep things in sync.
-
- if( !inName || ( *inName == '\0' ) )
- {
- name = gMDNSPtr->nicelabel;
- inFlags |= kDNSRegistrationFlagAutoRenameOnConflict;
- }
- else
- {
- MakeDomainLabelFromLiteralString( &name, inName );
- }
- MakeDomainNameFromDNSNameString( &type, inType );
- MakeDomainNameFromDNSNameString( &domain, inDomain );
-
- // Set up the host name (if not using the default).
-
- host = mDNSNULL;
- if( inHost )
- {
- host = &tempHost;
- MakeDomainNameFromDNSNameString( host, inHost );
- AppendDomainName( host, &domain );
- }
-
- // Register the service with mDNS.
-
- err = mDNS_RegisterService( gMDNSPtr, &objectPtr->set, &name, &type, &domain, host, mDNSOpaque16fromIntVal(inPort), textRecordPtr,
- (mDNSu16) inTextRecordSize, NULL, 0, interfaceID,
- DNSRegistrationPrivateCallBack, objectPtr );
- require_noerr( err, exit );
-
- if( outRef )
- {
- *outRef = objectPtr;
- }
-
-exit:
- if( err && objectPtr )
- {
- DNSRegistrationRemoveObject( objectPtr );
- DNSMemFree( objectPtr );
- }
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSNoSuchServiceRegistrationCreate
-//===========================================================================================================================
-
-DNSStatus
- DNSNoSuchServiceRegistrationCreate(
- DNSRegistrationFlags inFlags,
- const char * inName,
- const char * inType,
- const char * inDomain,
- const char * inInterfaceName,
- DNSRegistrationCallBack inCallBack,
- void * inCallBackContext,
- DNSRegistrationRef * outRef )
-{
- DNSStatus err;
- size_t size;
- DNSRegistration * objectPtr;
- mDNSInterfaceID interfaceID;
- domainlabel name;
- domainname type;
- domainname domain;
-
- objectPtr = mDNSNULL;
-
- // Check parameters.
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( ( inFlags & ~kDNSNoSuchServiceRegistrationCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- inFlags |= kDNSRegistrationFlagPrivateNoSuchService;
- require_action( inType, exit, err = kDNSBadParamErr );
- require_action( !inInterfaceName ||
- ( strlen( inInterfaceName ) < sizeof( objectPtr->interfaceName ) ), exit, err = kDNSBadParamErr );
-
- // Default to the local domain when a NULL, empty, or "." domain is passed in.
-
- if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
- {
- inDomain = kDNSLocalDomain;
- }
-
- // Allocate the object and set it up. If the TXT record is larger than the standard RDataBody, allocate more space.
-
- size = sizeof( *objectPtr );
-
- err = DNSMemAlloc( size, &objectPtr );
- require_noerr( err, exit );
- memset( objectPtr, 0, size );
-
- objectPtr->flags = inFlags;
- objectPtr->callback = inCallBack;
- objectPtr->callbackContext = inCallBackContext;
-
- // Set up the interface for interface-specific operations.
-
- if( inInterfaceName && ( *inInterfaceName != '\0' ) )
- {
- strcpy( objectPtr->interfaceName, inInterfaceName );
-
- err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
- require_noerr( err, exit );
- }
- else
- {
- interfaceID = mDNSInterface_Any;
- }
-
- // Add the object to the list.
-
- objectPtr->next = gDNSRegistrationList;
- gDNSRegistrationList = objectPtr;
-
- // Convert the name, type, domain, and port to a format suitable for mDNS. If the name is NULL or an empty string,
- // use the UTF-8 name of the system as the service name to make it easy for clients to use the standard name.
-
- if( !inName || ( *inName == '\0' ) )
- {
- name = gMDNSPtr->nicelabel;
- }
- else
- {
- MakeDomainLabelFromLiteralString( &name, inName );
- }
- MakeDomainNameFromDNSNameString( &type, inType );
- MakeDomainNameFromDNSNameString( &domain, inDomain );
-
- // Register the service with mDNS.
-
- err = mDNS_RegisterNoSuchService( gMDNSPtr, &objectPtr->set.RR_SRV, &name, &type, &domain, mDNSNULL,
- interfaceID, DNSNoSuchServiceRegistrationPrivateCallBack, objectPtr );
- require_noerr( err, exit );
-
- if( outRef )
- {
- *outRef = objectPtr;
- }
-
-exit:
- if( err && objectPtr )
- {
- DNSRegistrationRemoveObject( objectPtr );
- DNSMemFree( objectPtr );
- }
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSRegistrationRelease
-//===========================================================================================================================
-
-DNSStatus DNSRegistrationRelease( DNSRegistrationRef inRef, DNSRegistrationFlags inFlags )
-{
- DNSStatus err;
- DNSRegistrationEvent event;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( inRef, exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-
- // Notify the client of the registration release. Remove the object first so they cannot try to use it in the callback.
-
- inRef = DNSRegistrationRemoveObject( inRef );
- require_action( inRef, exit, err = kDNSBadReferenceErr );
-
- if( inRef->callback )
- {
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSRegistrationEventTypeRelease;
- inRef->callback( inRef->callbackContext, inRef, kDNSNoErr, &event );
- }
-
- // Deregister from mDNS after everything else since it will call us back to free the memory.
-
- if( !( inRef->flags & kDNSRegistrationFlagPrivateNoSuchService ) )
- {
- err = mDNS_DeregisterService( gMDNSPtr, &inRef->set );
- require_noerr( err, exit );
- }
- else
- {
- err = mDNS_DeregisterNoSuchService( gMDNSPtr, &inRef->set.RR_SRV );
- require_noerr( err, exit );
- }
-
- // Note: Don't free here. Wait for mDNS to call us back with a mem free result.
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSRegistrationUpdate
-//===========================================================================================================================
-
-DNSStatus
- DNSRegistrationUpdate(
- DNSRegistrationRef inRef,
- DNSRecordFlags inFlags,
- DNSRegistrationRecordRef inRecord,
- const void * inData,
- DNSCount inSize,
- DNSUInt32 inNewTTL )
-{
- DNSStatus err;
- AuthRecord * rr;
- size_t maxRDLength;
- RData * newRData;
-
- newRData = mDNSNULL;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( DNSRegistrationFindObject( inRef ), exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSRegistrationUpdateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- require_action( inData || ( inSize == 0 ), exit, err = kDNSBadParamErr );
-
- // If a non-NULL record is specified, update it. Otherwise, use the standard TXT record.
-
- if( inRecord )
- {
- // $$$ TO DO: Add support for updating extra records (support adding and removing them too).
-
- rr = mDNSNULL;
- err = kDNSUnsupportedErr;
- require_noerr( err, exit );
- }
- else
- {
- rr = &inRef->set.RR_TXT;
- }
-
- // Allocate storage for the new data and set it up.
-
- maxRDLength = sizeof( RDataBody );
- if( inSize > maxRDLength )
- {
- maxRDLength = inSize;
- }
- err = DNSMemAlloc( ( sizeof( *newRData ) - sizeof( RDataBody ) ) + maxRDLength, &newRData );
- require_noerr( err, exit );
-
- newRData->MaxRDLength = (mDNSu16) maxRDLength;
- memcpy( &newRData->u, inData, inSize );
-
- // Update the record with mDNS.
-
- err = mDNS_Update( gMDNSPtr, rr, inNewTTL, (mDNSu16) inSize, newRData, DNSRegistrationUpdateCallBack );
- require_noerr( err, exit );
-
- newRData = mDNSNULL;
-
-exit:
- if( newRData )
- {
- DNSMemFree( newRData );
- }
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSRegistrationPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSRegistrationPrivateCallBack( mDNS * const inMDNS, ServiceRecordSet * const inSet, mStatus inResult )
-{
- DNSRegistrationRef object;
- DNSRegistrationEvent event;
-
- DNS_UNUSED( inMDNS );
-
- DNSServicesLock();
-
- // Exit if object is no longer valid. Should never happen.
-
- object = (DNSRegistrationRef) inSet->ServiceContext;
- require( object, exit );
-
- // Dispatch based on the status code.
-
- switch( inResult )
- {
- case mStatus_NoError:
- debugf( DEBUG_NAME "registration callback: \"%##s\" name successfully registered", inSet->RR_SRV.resrec.name.c );
-
- // Notify the client of a successful registration.
-
- if( object->callback )
- {
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSRegistrationEventTypeRegistered;
- object->callback( object->callbackContext, object, kDNSNoErr, &event );
- }
- break;
-
- case mStatus_NameConflict:
- {
- DNSStatus err;
- mDNSBool removeIt;
-
- debugf( DEBUG_NAME "registration callback: \"%##s\" name conflict", inSet->RR_SRV.resrec.name.c );
-
- // Name conflict. If the auto-rename option is enabled, uniquely rename the service and re-register it. Otherwise,
- // remove the object so they cannot try to use it in the callback and notify the client of the name conflict.
-
- removeIt = mDNStrue;
- if( object->flags & kDNSRegistrationFlagAutoRenameOnConflict )
- {
- err = mDNS_RenameAndReregisterService( inMDNS, inSet, mDNSNULL );
- check_noerr( err );
- if( err == mStatus_NoError )
- {
- debugf( DEBUG_NAME "registration callback: auto-renamed to \"%##s\"", inSet->RR_SRV.resrec.name.c );
- removeIt = mDNSfalse;
- }
- }
- if( removeIt )
- {
- object = DNSRegistrationRemoveObject( object );
- require( object, exit );
-
- // Notify the client of the name collision.
-
- if( object->callback )
- {
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSRegistrationEventTypeNameCollision;
- object->callback( object->callbackContext, object, kDNSNoErr, &event );
- }
-
- // Notify the client that the registration is being released.
-
- if( object->callback )
- {
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSRegistrationEventTypeRelease;
- object->callback( object->callbackContext, object, kDNSNoErr, &event );
- }
-
- // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
-
- DNSMemFree( object );
- }
- break;
- }
-
- case mStatus_MemFree:
- debugf( DEBUG_NAME "registration callback: \"%##s\" memory free", inSet->RR_SRV.resrec.name.c );
-
- if( object->set.RR_TXT.resrec.rdata != &object->set.RR_TXT.rdatastorage )
- {
- // Standard TXT record was updated with new data so free that data separately.
-
- DNSMemFree( object->set.RR_TXT.resrec.rdata );
- }
- DNSMemFree( object );
- break;
-
- default:
- debugf( DEBUG_NAME "registration callback: \"%##s\" unknown result %d", inSet->RR_SRV.resrec.name.c, inResult );
- break;
- }
-
-exit:
- DNSServicesUnlock();
-}
-
-//===========================================================================================================================
-// DNSNoSuchServiceRegistrationPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSNoSuchServiceRegistrationPrivateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, mStatus inResult )
-{
- DNSRegistrationRef object;
- DNSRegistrationEvent event;
-
- DNS_UNUSED( inMDNS );
-
- DNSServicesLock();
-
- // Exit if object is no longer valid. Should never happen.
-
- object = (DNSRegistrationRef) inRR->RecordContext;
- require( object, exit );
-
- // Dispatch based on the status code.
-
- switch( inResult )
- {
- case mStatus_NoError:
- debugf( DEBUG_NAME "registration callback: \"%##s\" name successfully registered", inRR->resrec.name.c );
-
- // Notify the client of a successful registration.
-
- if( object->callback )
- {
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSRegistrationEventTypeRegistered;
- object->callback( object->callbackContext, object, kDNSNoErr, &event );
- }
- break;
-
- case mStatus_NameConflict:
- {
- debugf( DEBUG_NAME "registration callback: \"%##s\" name conflict", inRR->resrec.name.c );
-
- // Name conflict. Name conflicts for no-such-service registrations often do not make sense since the main goal
- // is to assert that no other service exists with a name. Because of this, name conflicts should be handled by
- // the code registering the no-such-service since it is likely that if another service is already using the
- // name that the service registering the no-such-service should rename its other services as well. The name
- // collision client callback invoked here can do any of this client-specific behavior. It may be worth adding
- // support for the auto-rename feature in the future though, if that becomes necessary.
-
- object = DNSRegistrationRemoveObject( object );
- require( object, exit );
-
- // Notify the client of the name collision.
-
- if( object->callback )
- {
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSRegistrationEventTypeNameCollision;
- object->callback( object->callbackContext, object, kDNSNoErr, &event );
- }
-
- // Notify the client that the registration is being released.
-
- if( object->callback )
- {
- memset( &event, 0, sizeof( event ) );
- event.type = kDNSRegistrationEventTypeRelease;
- object->callback( object->callbackContext, object, kDNSNoErr, &event );
- }
-
- // When a name conflict occurs, mDNS will not send a separate mem free result so free the memory here.
-
- DNSMemFree( object );
- break;
- }
-
- case mStatus_MemFree:
- debugf( DEBUG_NAME "registration callback: \"%##s\" memory free", inRR->resrec.name.c );
-
- DNSMemFree( object );
- break;
-
- default:
- debugf( DEBUG_NAME "registration callback: \"%##s\" unknown result %d", inRR->resrec.name.c, inResult );
- break;
- }
-
-exit:
- DNSServicesUnlock();
-}
-
-//===========================================================================================================================
-// DNSRegistrationUpdateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSRegistrationUpdateCallBack( mDNS * const inMDNS, AuthRecord * const inRR, RData *inOldData )
-{
- DNS_UNUSED( inMDNS );
-
- check( inRR );
- check( inOldData );
-
- if( inOldData != &inRR->rdatastorage )
- {
- DNSMemFree( inOldData );
- }
-}
-
-//===========================================================================================================================
-// DNSRegistrationFindObject
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSRegistrationRef * DNSRegistrationFindObject( DNSRegistrationRef inRef )
-{
- DNSRegistration ** p;
-
- for( p = &gDNSRegistrationList; *p; p = &( *p )->next )
- {
- if( *p == inRef )
- {
- break;
- }
- }
- return( p );
-}
-
-//===========================================================================================================================
-// DNSRegistrationRemoveObject
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSRegistrationRef DNSRegistrationRemoveObject( DNSRegistrationRef inRef )
-{
- DNSRegistration ** p;
- DNSRegistration * found;
-
- for( p = &gDNSRegistrationList; *p; p = &( *p )->next )
- {
- if( *p == inRef )
- {
- break;
- }
- }
- found = *p;
- if( found )
- {
- *p = found->next;
- }
- return( found );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Domain Registration ==
-#endif
-
-//===========================================================================================================================
-// DNSDomainRegistrationCreate
-//===========================================================================================================================
-
-DNSStatus
- DNSDomainRegistrationCreate(
- DNSDomainRegistrationFlags inFlags,
- const char * inName,
- DNSDomainRegistrationType inType,
- DNSDomainRegistrationRef * outRef )
-{
- DNSStatus err;
- DNSDomainRegistration * objectPtr;
-
- objectPtr = mDNSNULL;
-
- // Check parameters.
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( ( inFlags & ~kDNSDomainRegistrationCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- require_action( inName, exit, err = kDNSBadParamErr );
- require_action( inType < kDNSDomainRegistrationTypeMax, exit, err = kDNSBadParamErr );
-
- // Allocate the object and set it up.
-
- err = DNSMemAlloc( sizeof( *objectPtr ), &objectPtr );
- require_noerr( err, exit );
- memset( objectPtr, 0, sizeof( *objectPtr ) );
-
- objectPtr->flags = inFlags;
-
- // Add the object to the list.
-
- objectPtr->next = gDNSDomainRegistrationList;
- gDNSDomainRegistrationList = objectPtr;
-
- // Register the domain with mDNS.
-
- err = mDNS_AdvertiseDomains( gMDNSPtr, &objectPtr->rr, (mDNS_DomainType) inType, mDNSInterface_Any, (char *) inName );
- require_noerr( err, exit );
-
- if( outRef )
- {
- *outRef = objectPtr;
- }
-
-exit:
- if( err && objectPtr )
- {
- DNSDomainRegistrationRemoveObject( objectPtr );
- DNSMemFree( objectPtr );
- }
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSDomainRegistrationRelease
-//===========================================================================================================================
-
-DNSStatus DNSDomainRegistrationRelease( DNSDomainRegistrationRef inRef, DNSDomainRegistrationFlags inFlags )
-{
- DNSStatus err;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( inRef, exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSDomainRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-
- // Remove the object and deregister the domain with mDNS.
-
- inRef = DNSDomainRegistrationRemoveObject( inRef );
- require_action( inRef, exit, err = kDNSBadReferenceErr );
-
- mDNS_StopAdvertiseDomains( gMDNSPtr, &inRef->rr );
-
- // Release the memory used by the object.
-
- DNSMemFree( inRef );
- err = kDNSNoErr;
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSDomainRegistrationRemoveObject
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSDomainRegistrationRef DNSDomainRegistrationRemoveObject( DNSDomainRegistrationRef inRef )
-{
- DNSDomainRegistration ** p;
- DNSDomainRegistration * found;
-
- for( p = &gDNSDomainRegistrationList; *p; p = &( *p )->next )
- {
- if( *p == inRef )
- {
- break;
- }
- }
- found = *p;
- if( found )
- {
- *p = found->next;
- }
- return( found );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Domain Registration ==
-#endif
-
-//===========================================================================================================================
-// DNSHostRegistrationCreate
-//===========================================================================================================================
-
-DNSStatus
- DNSHostRegistrationCreate(
- DNSHostRegistrationFlags inFlags,
- const char * inName,
- const char * inDomain,
- const DNSNetworkAddress * inAddr,
- const char * inInterfaceName,
- DNSHostRegistrationCallBack inCallBack,
- void * inCallBackContext,
- DNSHostRegistrationRef * outRef )
-{
- DNSStatus err;
- domainname name;
- DNSHostRegistration * object;
- mDNSInterfaceID interfaceID;
- mDNSv4Addr ip;
- char buffer[ 64 ];
-
- object = mDNSNULL;
-
- // Check parameters.
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( ( inFlags & ~kDNSHostRegistrationCreateValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
- require_action( inName, exit, err = kDNSBadParamErr );
- require_action( inAddr && ( inAddr->addressType == kDNSNetworkAddressTypeIPv4 ), exit, err = kDNSUnsupportedErr );
- require_action( !inInterfaceName ||
- ( strlen( inInterfaceName ) < sizeof( object->interfaceName ) ), exit, err = kDNSBadParamErr );
-
- // Default to the local domain when a NULL, empty, or "." domain is passed in.
-
- if( !inDomain || ( inDomain[ 0 ] == '\0' ) || ( inDomain[ 0 ] == '.' ) )
- {
- inDomain = kDNSLocalDomain;
- }
-
- // If the caller only wants to add if not found, check if a host with this name was already registered.
-
- MakeDomainNameFromDNSNameString( &name, inName );
- AppendDNSNameString( &name, inDomain );
-
- if( inFlags & kDNSHostRegistrationFlagOnlyIfNotFound )
- {
- object = DNSHostRegistrationFindObjectByName( &name );
- if( object )
- {
- ++object->refCount;
- if( outRef )
- {
- *outRef = object;
- }
- object = mDNSNULL;
- err = kDNSNoErr;
- goto exit;
- }
- }
-
- // Allocate the object and set it up.
-
- err = DNSMemAlloc( sizeof( *object ), &object );
- require_noerr( err, exit );
- memset( object, 0, sizeof( *object ) );
-
- MakeDomainLabelFromLiteralString( &object->name, inName );
- MakeDomainLabelFromLiteralString( &object->domain, inDomain );
- object->refCount = 1;
- object->flags = inFlags;
- object->callback = inCallBack;
- object->callbackContext = inCallBackContext;
-
- // Set up the interface for interface-specific operations.
-
- if( inInterfaceName && ( *inInterfaceName != '\0' ) )
- {
- strcpy( object->interfaceName, inInterfaceName );
-
- err = mDNSPlatformInterfaceNameToID( gMDNSPtr, inInterfaceName, &interfaceID );
- require_noerr( err, exit );
- }
- else
- {
- interfaceID = mDNSInterface_Any;
- }
-
- // Convert the IP address to a format suitable for mDNS.
-
- ip.NotAnInteger = inAddr->u.ipv4.addr.v32;
-
- // Set up the resource records and name.
-
- mDNS_SetupResourceRecord( &object->RR_A, mDNSNULL, interfaceID, kDNSType_A, 60, kDNSRecordTypeUnique,
- DNSHostRegistrationPrivateCallBack, object );
- mDNS_SetupResourceRecord( &object->RR_PTR, mDNSNULL, interfaceID, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique,
- DNSHostRegistrationPrivateCallBack, object );
-
- AssignDomainName( &object->RR_A.resrec.name, &name );
-
- mDNS_snprintf( buffer, sizeof( buffer ), "%d.%d.%d.%d.in-addr.arpa.", ip.b[ 3 ], ip.b[ 2 ], ip.b[ 1 ], ip.b[ 0 ] );
- MakeDomainNameFromDNSNameString( &object->RR_PTR.resrec.name, buffer );
-
- object->RR_A.resrec.rdata->u.ipv4 = ip;
- AssignDomainName( &object->RR_PTR.resrec.rdata->u.name, &object->RR_A.resrec.name );
-
- // Add the object to the list.
-
- object->next = gDNSHostRegistrationList;
- gDNSHostRegistrationList = object;
-
- // Register with mDNS.
-
- err = mDNS_Register( gMDNSPtr, &object->RR_A );
- require_noerr( err, exit );
-
- err = mDNS_Register( gMDNSPtr, &object->RR_PTR );
- if( err != mStatus_NoError )
- {
- mDNS_Deregister( gMDNSPtr, &object->RR_A );
- }
- require_noerr( err, exit );
-
- if( outRef )
- {
- *outRef = object;
- }
-
-exit:
- if( err && object )
- {
- DNSHostRegistration ** p;
-
- p = DNSHostRegistrationFindObject( object );
- *p = object->next;
- DNSMemFree( object );
- }
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSHostRegistrationRelease
-//===========================================================================================================================
-
-DNSStatus DNSHostRegistrationRelease( DNSHostRegistrationRef inRef, DNSHostRegistrationFlags inFlags )
-{
- DNSStatus err;
- DNSHostRegistrationRef * p;
-
- DNSServicesLock();
- require_action( gMDNSPtr, exit, err = kDNSNotInitializedErr );
- require_action( inRef, exit, err = kDNSBadReferenceErr );
- require_action( ( inFlags & ~kDNSHostRegistrationReleaseValidFlags ) == 0, exit, err = kDNSBadFlagsErr );
-
- // Decrement the reference count and if it drops to 0, remove the object and deregister with mDNS.
-
- p = DNSHostRegistrationFindObject( inRef );
- inRef = *p;
- require_action( inRef, exit, err = kDNSBadReferenceErr );
-
- check( inRef->refCount > 0 );
- if( --inRef->refCount == 0 )
- {
- *p = inRef->next;
-
- mDNS_Deregister( gMDNSPtr, &inRef->RR_A );
- mDNS_Deregister( gMDNSPtr, &inRef->RR_PTR );
-
- // Release the memory used by the object.
-
- DNSMemFree( inRef );
- }
- err = kDNSNoErr;
-
-exit:
- DNSServicesUnlock();
- return( err );
-}
-
-//===========================================================================================================================
-// DNSHostRegistrationFindObject
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSHostRegistrationRef * DNSHostRegistrationFindObject( DNSHostRegistrationRef inRef )
-{
- DNSHostRegistration ** p;
-
- for( p = &gDNSHostRegistrationList; *p; p = &( *p )->next )
- {
- if( *p == inRef )
- {
- break;
- }
- }
- return( p );
-}
-
-//===========================================================================================================================
-// DNSHostRegistrationFindObjectByName
-//
-// Warning: Assumes the DNS lock is held.
-//===========================================================================================================================
-
-mDNSlocal DNSHostRegistrationRef DNSHostRegistrationFindObjectByName( const domainname *inName )
-{
- DNSHostRegistration * p;
-
- check( inName );
-
- for( p = gDNSHostRegistrationList; p; p = p->next )
- {
- if( SameDomainName( &p->RR_A.resrec.name, inName ) )
- {
- break;
- }
- }
- return( p );
-}
-
-//===========================================================================================================================
-// DNSHostRegistrationPrivateCallBack
-//===========================================================================================================================
-
-mDNSlocal void DNSHostRegistrationPrivateCallBack( mDNS * const inMDNS, AuthRecord *const inRR, mStatus inResult )
-{
- DNSHostRegistrationRef object;
-
- DNS_UNUSED( inMDNS );
-
- DNSServicesLock();
-
- // Exit if object is no longer valid. Should never happen.
-
- object = (DNSHostRegistrationRef) inRR->RecordContext;
- require( object, exit );
-
- // Dispatch based on the status code.
-
- if( inResult == mStatus_NoError )
- {
- debugf( DEBUG_NAME "host registration callback: \"%##s\" name successfully registered", inRR->resrec.name.c );
- if( object->callback )
- {
- object->callback( object->callbackContext, object, kDNSNoErr, mDNSNULL );
- }
- }
- else if( inResult == mStatus_NameConflict )
- {
- debugf( DEBUG_NAME "host registration callback: \"%##s\" name conflict", inRR->resrec.name.c );
-
- if( object->flags & kDNSHostRegistrationFlagAutoRenameOnConflict )
- {
- DNSStatus err;
- domainname name;
-
- // De-register any resource records still registered.
-
- if( object->RR_A.resrec.RecordType )
- {
- mDNS_Deregister( gMDNSPtr, &object->RR_A );
- }
- if( object->RR_PTR.resrec.RecordType )
- {
- mDNS_Deregister( gMDNSPtr, &object->RR_PTR );
- }
-
- // Rename the host and re-register to try again.
-
- IncrementLabelSuffix( &object->name, mDNSfalse );
- name.c[ 0 ] = 0;
- AppendDomainLabel( &name, &object->name );
- AppendDomainLabel( &name, &object->domain );
- AssignDomainName( &object->RR_PTR.resrec.name, &name );
-
- err = mDNS_Register( gMDNSPtr, &object->RR_A );
- check_noerr( err );
-
- err = mDNS_Register( gMDNSPtr, &object->RR_PTR );
- check_noerr( err );
- }
- else
- {
- if( object->callback )
- {
- object->callback( object->callbackContext, object, kDNSNameConflictErr, mDNSNULL );
- }
- }
- }
- else
- {
- debugf( DEBUG_NAME "host registration callback: \"%##s\" unknown result", inRR->resrec.name.c, inResult );
- }
-
-exit:
- DNSServicesUnlock();
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-//===========================================================================================================================
-// DNSMemAlloc
-//===========================================================================================================================
-
-mDNSlocal DNSStatus DNSMemAlloc( size_t inSize, void *outMem )
-{
- void * mem;
-
- check( inSize > 0 );
- check( outMem );
-
- mem = malloc( inSize );
- *( (void **) outMem ) = mem;
- if( mem )
- {
- return( kDNSNoErr );
- }
- return( kDNSNoMemoryErr );
-}
-
-//===========================================================================================================================
-// DNSMemFree
-//===========================================================================================================================
-
-mDNSlocal void DNSMemFree( void *inMem )
-{
- check( inMem );
-
- free( inMem );
-}
-
-//===========================================================================================================================
-// DNSDynamicTextRecordBuildEscaped
-//===========================================================================================================================
-
-DNSStatus DNSDynamicTextRecordBuildEscaped( const char *inFormat, void *outTextRecord, size_t *outSize )
-{
- DNSStatus err;
- size_t size;
- void * textRecord;
-
- textRecord = NULL;
-
- // Calculate the size of the built text record, allocate a buffer for it, then build it in that buffer.
-
- err = DNSTextRecordValidate( inFormat, 0x7FFFFFFF, NULL, &size );
- require_noerr( err, exit );
-
- textRecord = malloc( size );
- require_action( textRecord, exit, err = kDNSNoMemoryErr );
-
- err = DNSTextRecordValidate( inFormat, size, textRecord, &size );
- require_noerr( err, exit );
-
- // Success!
-
- if( outTextRecord )
- {
- *( (void **) outTextRecord ) = textRecord;
- textRecord = NULL;
- }
- if( outSize )
- {
- *outSize = size;
- }
-
-exit:
- if( textRecord )
- {
- free( textRecord );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// DNSDynamicTextRecordAppendCString
-//===========================================================================================================================
-
-DNSStatus DNSDynamicTextRecordAppendCString( void *ioTxt, size_t *ioTxtSize, const char *inName, const char *inValue )
-{
- DNSStatus err;
- size_t valueSize;
-
- require_action( inName, exit, err = kDNSBadParamErr );
- require_action( inValue, exit, err = kDNSBadParamErr );
-
- if( inValue != kDNSTextRecordStringNoValue )
- {
- valueSize = strlen( inValue );
- }
- else
- {
- valueSize = kDNSTextRecordNoSize;
- }
- err = DNSDynamicTextRecordAppendData( ioTxt, ioTxtSize, inName, inValue, valueSize );
- require_noerr( err, exit );
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSDynamicTextRecordAppendData
-//===========================================================================================================================
-
-DNSStatus
- DNSDynamicTextRecordAppendData(
- void * ioTxt,
- size_t * ioTxtSize,
- const char * inName,
- const void * inValue,
- size_t inValueSize )
-{
- DNSStatus err;
- size_t oldSize;
- size_t newSize;
- int hasName;
- int hasValue;
- void ** bufferPtr;
- void * newBuffer;
-
- require_action( ioTxt, exit, err = kDNSBadParamErr );
- require_action( ioTxtSize, exit, err = kDNSBadParamErr );
- require_action( inName, exit, err = kDNSBadParamErr );
-
- // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
-
- hasName = ( inName != kDNSTextRecordStringNoValue ) && ( *inName != '\0' );
- hasValue = ( inValue != kDNSTextRecordNoValue ) && ( inValueSize != kDNSTextRecordNoSize );
- require_action( hasName || hasValue, exit, err = kDNSUnsupportedErr );
-
- // Calculate the size needed for the new data (old size + length byte + name size + '=' + value size).
-
- oldSize = *ioTxtSize;
- newSize = oldSize + 1; // add length byte size
- if( hasName )
- {
- newSize += strlen( inName ); // add name size
- if( hasValue )
- {
- newSize += 1; // add '=' size
- }
- }
- if( hasValue )
- {
- newSize += inValueSize; // add value size
- }
-
- // Reallocate the buffer to make room for the new data.
-
- bufferPtr = (void **) ioTxt;
- newBuffer = realloc( *bufferPtr, newSize );
- require_action( newBuffer, exit, err = kDNSNoMemoryErr );
- *bufferPtr = newBuffer;
-
- err = DNSTextRecordAppendData( newBuffer, oldSize, newSize, inName, inValue, inValueSize, &newSize );
- require_noerr( err, exit );
-
- // Success!
-
- *ioTxtSize = newSize;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSDynamicTextRecordRelease
-//===========================================================================================================================
-
-void DNSDynamicTextRecordRelease( void *inTxt )
-{
- if( inTxt )
- {
- free( inTxt );
- }
-}
-
-//===========================================================================================================================
-// DNSTextRecordAppendCString
-//===========================================================================================================================
-
-DNSStatus
- DNSTextRecordAppendCString(
- void * inTxt,
- size_t inTxtSize,
- size_t inTxtMaxSize,
- const char * inName,
- const char * inValue,
- size_t * outTxtSize )
-{
- DNSStatus err;
- size_t valueSize;
-
- require_action( inName, exit, err = kDNSBadParamErr );
- require_action( inValue, exit, err = kDNSBadParamErr );
-
- if( inValue != kDNSTextRecordStringNoValue )
- {
- valueSize = strlen( inValue );
- }
- else
- {
- valueSize = kDNSTextRecordNoSize;
- }
- err = DNSTextRecordAppendData( inTxt, inTxtSize, inTxtMaxSize, inName, inValue, valueSize, outTxtSize );
- require_noerr( err, exit );
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSTextRecordAppendData
-//===========================================================================================================================
-
-DNSStatus
- DNSTextRecordAppendData(
- void * inTxt,
- size_t inTxtSize,
- size_t inTxtMaxSize,
- const char * inName,
- const void * inValue,
- size_t inValueSize,
- size_t * outTxtSize )
-{
- DNSStatus err;
- mDNSu8 * p;
- int hasName;
- int hasValue;
- size_t size;
- size_t newSize;
- const mDNSu8 * q;
-
- require_action( inTxt, exit, err = kDNSBadParamErr );
- require_action( inName, exit, err = kDNSBadParamErr );
-
- // Check for special flags to indicate no name or no value is used (e.g. "color" instead of "color=").
-
- hasName = ( inName != kDNSTextRecordStringNoValue ) && ( *inName != '\0' );
- hasValue = ( inValue != kDNSTextRecordNoValue ) && ( inValueSize != kDNSTextRecordNoSize );
- require_action( hasName || hasValue, exit, err = kDNSUnsupportedErr );
-
- // Calculate the size and make sure there is enough total room and enough room in an individual segment.
-
- size = 0;
- if( hasName )
- {
- size += strlen( inName ); // add name size
- if( hasValue )
- {
- size += 1; // add '=' size
- }
- }
- if( hasValue )
- {
- size += inValueSize; // add value size
- }
- newSize = inTxtSize + 1 + size; // old size + length byte + new data
-
- require_action( size < 256, exit, err = kDNSNoMemoryErr );
- require_action( newSize <= inTxtMaxSize, exit, err = kDNSNoMemoryErr );
-
- // Write the length-prefix byte containing the size of this segment.
-
- p = ( (mDNSu8 *) inTxt ) + inTxtSize;
- *p++ = (mDNSu8) size;
-
- // Copy the name.
-
- if( hasName )
- {
- q = (const mDNSu8 *) inName;
- while( *q != '\0' )
- {
- *p++ = *q++;
- }
- if( hasValue )
- {
- *p++ = '=';
- }
- }
- if( hasValue )
- {
- // Copy the value.
-
- q = (const mDNSu8 *) inValue;
- while( inValueSize-- > 0 )
- {
- *p++ = *q++;
- }
- }
-
- // Success!
-
- if( outTxtSize )
- {
- *outTxtSize = newSize;
- }
- err = kDNSNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSTextRecordEscape
-//===========================================================================================================================
-
-DNSStatus DNSTextRecordEscape( const void *inTextRecord, size_t inTextSize, char **outEscapedString )
-{
- DNSStatus err;
- const DNSUInt8 * src;
- const DNSUInt8 * end;
- DNSUInt8 * dstStorage;
- DNSUInt8 * dst;
- int size;
-
- check( inTextRecord || ( inTextSize == 0 ) );
-
- // Mac OS X uses a single null-terminated string to hold all the text record data with a \001 byte to delimit
- // individual records within the entire block. The following code converts a packed array of length-prefixed
- // records into a single \001-delimited, null-terminated string. Allocate size + 1 for the null terminator.
-
- dstStorage = (DNSUInt8 *) malloc( inTextSize + 1 );
- require_action( dstStorage, exit, err = kDNSNoMemoryErr );
- dst = dstStorage;
-
- if( inTextSize > 0 )
- {
- src = (const DNSUInt8 *) inTextRecord;
- end = src + inTextSize;
- while( src < end )
- {
- size = *src++;
- if( ( src + size ) > end )
- {
- // Malformed TXT record. Most likely an old-style TXT record.
-
- src = NULL;
- break;
- }
- while( size-- > 0 )
- {
- *dst++ = *src++;
- }
- *dst++ = '\001'; // \001 record separator. May be overwritten later if this is the last record.
- }
- check( (size_t)( dst - dstStorage ) <= inTextSize );
- if( src != end )
- {
- // Malformed TXT record. Assume an old-style TXT record and use the TXT record as a whole.
-
- memcpy( dstStorage, inTextRecord, inTextSize );
- dstStorage[ inTextSize ] = '\0';
- }
- else
- {
- dstStorage[ inTextSize - 1 ] = '\0';
- }
- }
- else
- {
- // No text record data so just return an empty string.
-
- *dst = '\0';
- }
-
- // Success!
-
- if( outEscapedString )
- {
- *outEscapedString = (char *) dstStorage;
- dstStorage = NULL;
- }
- err = kDNSNoErr;
-
-exit:
- if( dstStorage )
- {
- free( dstStorage );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// DNSNameValidate
-//===========================================================================================================================
-
-DNSStatus DNSNameValidate( const char *inName )
-{
- DNSStatus err;
- mDNSu8 * p;
- domainname name;
-
- p = MakeDomainNameFromDNSNameString( &name, inName );
- if( p )
- {
- err = kDNSNoErr;
- }
- else
- {
- err = kDNSBadParamErr;
- }
- return( err );
-}
-
-//===========================================================================================================================
-// DNSServiceTypeValidate
-//===========================================================================================================================
-
-DNSStatus DNSServiceTypeValidate( const char *inServiceType )
-{
- DNSStatus err;
- mDNSu8 * p;
- domainname type;
- domainname domain;
- domainname fqdn;
-
- // Construct a fake fully-qualified domain name with a known good domain and the service type to be verified since
- // there is currently no canned way to test just a service type by itself.
-
- p = MakeDomainNameFromDNSNameString( &type, inServiceType );
- if( !p )
- {
- err = kDNSBadParamErr;
- goto exit;
- }
-
- p = MakeDomainNameFromDNSNameString( &domain, "local." );
- if( !p )
- {
- err = kDNSBadParamErr;
- goto exit;
- }
-
- p = ConstructServiceName( &fqdn, mDNSNULL, &type, &domain );
- if( !p )
- {
- err = kDNSBadParamErr;
- goto exit;
- }
-
- err = kDNSNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSTextRecordValidate
-//===========================================================================================================================
-
-DNSStatus DNSTextRecordValidate( const char *inText, size_t inMaxSize, void *outRecord, size_t *outActualSize )
-{
- DNSStatus err;
- const mDNSu8 * p;
- size_t totalSize;
- mDNSu8 sectionSize;
- mDNSu8 * dst;
- mDNSu8 * section;
-
- require_action( inText, exit, err = kDNSBadParamErr );
-
- // A DNS TXT record consists of a packed block of length-prefixed strings of up to 255 characters each. To allow
- // this to be described with a null-terminated C-string, a special escape sequence of \001 is used to separate
- // individual character strings within the C-string.
-
- totalSize = 0;
- sectionSize = 0;
- dst = (mDNSu8 *) outRecord;
- section = dst;
-
- p = (const mDNSu8 *) inText;
- while( *p != '\0' )
- {
- ++totalSize;
- if( totalSize >= inMaxSize )
- {
- err = kDNSBadParamErr;
- goto exit;
- }
-
- if( *p == '\001' )
- {
- // Separator Escape sequence, start a new string section.
-
- if( sectionSize <= 0 )
- {
- err = kDNSBadParamErr;
- goto exit;
- }
- sectionSize = 0;
- if( section )
- {
- section = &dst[ totalSize ];
- section[ 0 ] = 0;
- }
- }
- else
- {
- if( sectionSize >= 255 )
- {
- err = kDNSBadParamErr;
- goto exit;
- }
- ++sectionSize;
- if( section )
- {
- section[ 0 ] = sectionSize;
- section[ sectionSize ] = *p;
- }
- }
- ++p;
- }
- ++totalSize;
-
- // Success!
-
- if( outActualSize )
- {
- *outActualSize = totalSize;
- }
- err = kDNSNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// MDNSAddrToDNSAddress
-//===========================================================================================================================
-
-mDNSlocal void MDNSAddrToDNSAddress( const mDNSAddr *inAddr, mDNSIPPort inPort, DNSNetworkAddress *outAddr )
-{
- switch( inAddr->type )
- {
- case mDNSAddrType_IPv4:
- outAddr->addressType = kDNSNetworkAddressTypeIPv4;
- outAddr->u.ipv4.addr.v32 = inAddr->ip.v4.NotAnInteger;
- outAddr->u.ipv4.port.v16 = inPort.NotAnInteger;
- break;
-
- case mDNSAddrType_IPv6:
- outAddr->addressType = kDNSNetworkAddressTypeIPv6;
- outAddr->u.ipv6.addr.v32[ 0 ] = inAddr->ip.v6.l[ 0 ];
- outAddr->u.ipv6.addr.v32[ 1 ] = inAddr->ip.v6.l[ 1 ];
- outAddr->u.ipv6.addr.v32[ 2 ] = inAddr->ip.v6.l[ 2 ];
- outAddr->u.ipv6.addr.v32[ 3 ] = inAddr->ip.v6.l[ 3 ];
- outAddr->u.ipv6.port.v16 = inPort.NotAnInteger;
- break;
-
- default:
- outAddr->addressType = kDNSNetworkAddressTypeInvalid;
- break;
- }
-}
-
-#ifdef __cplusplus
- }
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: DNSServices.h,v $
-Revision 1.11 2004/07/13 21:24:28 rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.10 2004/01/30 02:56:34 bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.9 2003/10/31 12:16:03 bradley
-Added support for providing the resolved host name to the callback.
-
-Revision 1.8 2003/08/20 06:44:24 bradley
-Updated to latest internal version of the mDNSCore code: Added support for interface
-specific registrations; Added support for no-such-service registrations; Added support for host
-name registrations; Added support for host proxy and service proxy registrations; Added support for
-registration record updates (e.g. TXT record updates); Added support for using either a single C
-string TXT record, a raw, pre-formatted TXT record potentially containing multiple character string
-entries, or a C-string containing a Mac OS X-style \001-delimited set of TXT record character
-strings; Added support in resolve callbacks for providing both a simplified C-string for TXT records
-and a ptr/size for the raw TXT record data; Added utility routines for dynamically building TXT
-records from a variety of sources (\001-delimited, individual strings, etc.) and converting TXT
-records to various formats for use in apps; Added utility routines to validate DNS names, DNS
-service types, and TXT records; Moved to portable address representation unions (byte-stream vs host
-order integer) for consistency, to avoid swapping between host and network byte order, and for IPv6
-support; Removed dependence on modified mDNSCore: define structures and prototypes locally; Added
-support for automatically renaming services on name conflicts; Detect and correct TXT records from
-old versions of mDNS that treated a TXT record as an arbitrary block of data, but prevent other
-malformed TXT records from being accepted; Added many more error codes; Added complete HeaderDoc for
-all constants, structures, typedefs, macros, and functions. Various other minor cleanup and fixes.
-
-Revision 1.7 2003/08/12 19:56:29 cheshire
-Update to APSL 2.0
-
-Revision 1.6 2003/07/02 21:20:10 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.5 2003/03/22 02:57:45 cheshire
-Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.4 2003/02/20 00:59:05 cheshire
-Brought Windows code up to date so it complies with
-Josh Graessley's interface changes for IPv6 support.
-(Actual support for IPv6 on Windows will come later.)
-
-Revision 1.3 2002/09/21 20:44:57 zarzycki
-Added APSL info
-
-Revision 1.2 2002/09/20 05:58:02 bradley
-DNS Services for Windows
-
-*/
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @header DNSServices
-
- @abstract DNS Services interfaces.
-
- @discussion
-
- DNS Services provides DNS service registration, domain and service discovery, and name resolving services.
-*/
-
-#ifndef __DNS_SERVICES__
-#define __DNS_SERVICES__
-
-#include <stddef.h>
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#if 0
-#pragma mark == General ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined dns_check_compile_time
-
- @abstract Performs a compile-time check of something such as the size of an int.
-
- @discussion
-
- This declares a unique array with a size that is determined by dividing 1 by the result of the compile-time expression
- passed to the macro. If the expression evaluates to 0, this expression results in a divide by zero, which is illegal
- and generates a compile-time error.
-
- For example:
-
- dns_check_compile_time( sizeof( int ) == 4 );
-
- Note: This only works with compile-time expressions.
- Note: This only works in places where extern declarations are allowed (e.g. global scope).
-
- References:
-
- <http://www.jaggersoft.com/pubs/CVu11_3.html>
- <http://www.jaggersoft.com/pubs/CVu11_5.html>
-
- Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not
- work with GCC due to GCC allow a zero-length array. Using a divide-by-zero condition turned out to be more portable.
-*/
-
-#define dns_check_compile_time( X ) extern int dns_unique_name[ 1 / (int)( ( X ) ) ]
-
-#define dns_unique_name dns_make_name_wrapper( __LINE__ )
-#define dns_make_name_wrapper( X ) dns_make_name( X )
-#define dns_make_name( X ) dns_check_compile_time_ ## X
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined dns_check_compile_time_code
-
- @abstract Perform a compile-time check, suitable for placement in code, of something such as the size of an int.
-
- @discussion
-
- This creates a switch statement with an existing case for 0 and an additional case using the result of a
- compile-time expression. A switch statement cannot have two case labels with the same constant so if the
- compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time
- expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error.
-
- For example:
-
- dns_check_compile_time_code( sizeof( int ) == 4 );
-
- Note: This only works with compile-time expressions.
- Note: This does not work in a global scope so it must be inside a function.
-
- References:
-
- <http://www.jaggersoft.com/pubs/CVu11_3.html>
- <http://www.jaggersoft.com/pubs/CVu11_5.html>
-*/
-
-#define dns_check_compile_time_code( X ) switch( 0 ) { case 0: case X:; }
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DNS_LOCAL
-
- @abstract Macro to make variables and functions static when debugging is off, but exported when debugging is on.
-
- @discussion
-
- Rather than using "static" directly, using this macros allows you to access these variables external while
- debugging without being penalized for production builds.
-*/
-
-#if( DEBUG )
- #define DNS_LOCAL
-#else
- #define DNS_LOCAL static
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DNS_EXPORT
-
- @abstract Macro to provide a visual clue that a variable or function is globally visible.
-*/
-
-#define DNS_EXPORT
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DNS_DEBUG_USE_ONLY
- @abstract Macro to mark a variable as unused when debugging is turned off.
- @discussion
-
- Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables
- generate compiler warnings about unused variables. To eliminate these warnings, use the DNS_DEBUG_USE_ONLY macro
- to indicate the variables are for debugging only.
-*/
-
-#if( DEBUG )
- #define DNS_DEBUG_USE_ONLY( X )
-#else
- #define DNS_DEBUG_USE_ONLY( X ) (void)( X )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DNS_UNUSED
- @abstract Macro to mark a variable as unused.
- @discussion
-
- There is no universally supported pragma/attribute for indicating a variable is unused. DNS_UNUSED lets
- indicate a variable is unused in a manner that is supported by most compilers.
-*/
-
-#define DNS_UNUSED( X ) (void)( X )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSUInt8
-
- @abstract 8-bit unsigned data type.
-*/
-
-typedef unsigned char DNSUInt8;
-
-dns_check_compile_time( sizeof( DNSUInt8 ) == 1 );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSUInt16
-
- @abstract 16-bit unsigned data type.
-*/
-
-typedef unsigned short DNSUInt16;
-
-dns_check_compile_time( sizeof( DNSUInt16 ) == 2 );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSUInt32
-
- @abstract 32-bit unsigned data type.
-*/
-
-typedef unsigned long DNSUInt32;
-
-dns_check_compile_time( sizeof( DNSUInt32 ) == 4 );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSSInt32
-
- @abstract 32-bit signed data type.
-*/
-
-typedef signed long DNSSInt32;
-
-dns_check_compile_time( sizeof( DNSSInt32 ) == 4 );
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSOpaque16
-
- @abstract 16-bit opaque data type with 8-bit and 16-bit accessors.
-*/
-
-typedef union DNSOpaque16 DNSOpaque16;
-union DNSOpaque16
-{
- DNSUInt8 v8[ 2 ];
- DNSUInt16 v16;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSOpaque32
-
- @abstract 32-bit opaque data type with 8-bit, 16-bit, and 32-bit accessors.
-*/
-
-typedef union DNSOpaque32 DNSOpaque32;
-union DNSOpaque32
-{
- DNSUInt8 v8[ 4 ];
- DNSUInt16 v16[ 2 ];
- DNSUInt32 v32;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSOpaque128
-
- @abstract 128-bit opaque data type with 8-bit, 16-bit, and 32-bit accessors.
-*/
-
-typedef union DNSOpaque128 DNSOpaque128;
-union DNSOpaque128
-{
- DNSUInt8 v8[ 16 ];
- DNSUInt16 v16[ 8 ];
- DNSUInt32 v32[ 4 ];
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSCount
-
- @abstract Count of at least 32-bits.
-*/
-
-typedef DNSUInt32 DNSCount;
-
-#if 0
-#pragma mark == Errors ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSStatus
-
- @abstract DNS Service status code.
-
- @constant kDNSNoErr (0) Success. No error occurred.
- @constant kDNSUnknownErr (-65537) An unknown error occurred.
- @constant kDNSNoSuchNameErr (-65538) The name could not be found on the network.
- @constant kDNSNoMemoryErr (-65539) Not enough memory was available.
- @constant kDNSBadParamErr (-65540) A invalid or inappropriate parameter was specified.
- @constant kDNSBadReferenceErr (-65541) A invalid or inappropriate reference was specified.
- @constant kDNSBadStateErr (-65542) The current state does not allow the specified operation.
- @constant kDNSBadFlagsErr (-65543) An invalid, inappropriate, or unsupported flag was specified.
- @constant kDNSUnsupportedErr (-65544) The specified feature is not currently supported.
- @constant kDNSNotInitializedErr (-65545) DNS Service has not been initialized.
- @constant kDNSNoCacheErr (-65546) No cache was specified.
- @constant kDNSAlreadyRegisteredErr (-65547) Service or host name is already registered.
- @constant kDNSNameConflictErr (-65548) Name conflicts with another on the network.
- @constant kDNSInvalidErr (-65549) A general error to indicate something is invalid.
- @constant kDNSGrowCache (-65550) Cache needs to be grown (not used).
- @constant kDNSIncompatibleErr (-65551) Version is incompatible.
-
- @constant kDNSSizeErr (-65600) Size was too small or too big.
- @constant kDNSMismatchErr (-65601) A data, version, etc. mismatch occurred.
- @constant kDNSReadErr (-65602) Read failed.
- @constant kDNSWriteErr (-65603) Write failed.
- @constant kDNSCanceledErr (-65604) Operation was canceled.
- @constant kDNSTimeoutErr (-65605) Operation timed out.
- @constant kDNSConnectionErr (-65606) A disconnect or other connection error occurred.
- @constant kDNSInUseErr (-65607) Object is in use (e.g. cannot reuse active param blocks).
- @constant kDNSNoResourcesErr (-65608) Resources unavailable to perform the operation.
- @constant kDNSEndingErr (-65609) Connection, session, or something is ending.
-
- @constant kDNSConfigChanged (-65791) Configuration changed (not used).
- @constant kDNSMemFree (-65792) Memory can be freed.
-*/
-
-typedef DNSSInt32 DNSStatus;
-enum
-{
- kDNSNoErr = 0,
-
- // DNS Services error codes are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537).
-
- kDNSStartErr = -65537, // 0xFFFE FFFF
-
- kDNSUnknownErr = -65537,
- kDNSNoSuchNameErr = -65538,
- kDNSNoMemoryErr = -65539,
- kDNSBadParamErr = -65540,
- kDNSBadReferenceErr = -65541,
- kDNSBadStateErr = -65542,
- kDNSBadFlagsErr = -65543,
- kDNSUnsupportedErr = -65544,
- kDNSNotInitializedErr = -65545,
- kDNSNoCacheErr = -65546,
- kDNSAlreadyRegisteredErr = -65547,
- kDNSNameConflictErr = -65548,
- kDNSInvalidErr = -65549,
- kDNSGrowCache = -65550, // Reserved for mDNSCore
- kDNSIncompatibleErr = -65551,
-
- kDNSSizeErr = -65600,
- kDNSMismatchErr = -65601,
- kDNSReadErr = -65602,
- kDNSWriteErr = -65603,
- kDNSCanceledErr = -65604,
- kDNSTimeoutErr = -65605,
- kDNSConnectionErr = -65606,
- kDNSInUseErr = -65607,
- kDNSNoResourcesErr = -65608,
- kDNSEndingErr = -65609,
-
- kDNSConfigChanged = -65791, // Reserved for mDNSCore
- kDNSMemFree = -65792, // Reserved for mDNSCore
-
- kDNSEndErr = -65792 // 0xFFFE FF00
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSFlags
-
- @abstract Flags used control DNS Services.
-
- @constant kDNSFlagAdvertise
- Indicates that interfaces should be advertised on the network. Software that only performs searches
- do not need to set this flag.
-*/
-
-typedef DNSUInt32 DNSFlags;
-enum
-{
- kDNSFlagAdvertise = ( 1 << 0 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSPort
-
- @abstract UDP/TCP port for DNS services.
-
- @constant kDNSPortInvalid
- Invalid port.
-
- @constant kDNSPortUnicastDNS
- TCP/UDP port for normal unicast DNS (see RFC 1035).
-
- @constant kDNSPortMulticastDNS
- TCP/UDP port for Multicast DNS (see <http://www.multicastdns.org/>).
-*/
-
-typedef DNSUInt16 DNSPort;
-enum
-{
- kDNSPortInvalid = 0,
- kDNSPortUnicastDNS = 53,
- kDNSPortMulticastDNS = 5353
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSNetworkAddressType
-
- @abstract Type of address data within a DNSNetworkAddress.
-
- @constant kDNSNetworkAddressTypeInvalid
- Invalid type.
-
- @constant kDNSNetworkAddressTypeIPv4
- IPv4 address data.
-
- @constant kDNSNetworkAddressTypeIPv6
- IPv6 address data.
-*/
-
-typedef DNSUInt32 DNSNetworkAddressType;
-
-#define kDNSNetworkAddressTypeInvalid 0
-#define kDNSNetworkAddressTypeIPv4 4
-#define kDNSNetworkAddressTypeIPv6 6
-#define kDNSNetworkAddressTypeAny 0xFFFFFFFF
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSNetworkAddressIPv4
-
- @field addr
- 32-bit IPv4 address in network byte order.
-
- @field port
- 16-bit port number in network byte order.
-*/
-
-typedef struct DNSNetworkAddressIPv4 DNSNetworkAddressIPv4;
-struct DNSNetworkAddressIPv4
-{
- DNSOpaque32 addr;
- DNSOpaque16 port;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSNetworkAddressIPv6
-
- @field addr
- 128-bit IPv6 address in network byte order.
-
- @field port
- 16-bit port number in network byte order.
-*/
-
-typedef struct DNSNetworkAddressIPv6 DNSNetworkAddressIPv6;
-struct DNSNetworkAddressIPv6
-{
- DNSOpaque128 addr;
- DNSOpaque16 port;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSNetworkAddress
-
- @field addressType
- Type of data contained within the address structure.
-
- @field ipv4
- IPv4 address data.
-
- @field reserved
- Reserved data (pads structure to allow for future growth). Unused portions must be zero.
-*/
-
-typedef struct DNSNetworkAddress DNSNetworkAddress;
-struct DNSNetworkAddress
-{
- DNSNetworkAddressType addressType;
- union
- {
- DNSNetworkAddressIPv4 ipv4;
- DNSNetworkAddressIPv6 ipv6;
- } u;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined kDNSLocalDomain
-
- @abstract Local DNS domain name (local.).
-*/
-
-#define kDNSLocalDomain "local."
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSServicesInitialize
-
- @abstract Initializes DNS Services. This must be called before DNS Services functions can be used.
-
- @param inFlags
- Flags to control DNS Services.
-
- @param inCacheEntryCount
- Number of entries in the DNS record cache. Specify 0 to use the default.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSServicesInitialize( DNSFlags inFlags, DNSCount inCacheEntryCount );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSServicesFinalize
-
- @abstract Finalizes DNS Services. No DNS Services functions may be called after this function is called.
-*/
-
-void DNSServicesFinalize( void );
-
-#if 0
-#pragma mark == Resolving ==
-#endif
-
-//===========================================================================================================================
-// Resolving
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSBrowserRef
-
- @abstract Reference to a DNS browser object.
-
- @discussion
-
- A browser object is typically used by a graphical user application in a manner similar to the Macintosh "Chooser"
- application. The application creates a browser object then starts domain and/or service searches to begin browsing.
- When domains and/or services are found, added, or removed, the application is notified via a callback routine.
-*/
-
-typedef struct DNSBrowser * DNSBrowserRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSResolverRef
-
- @abstract Reference to a DNS resolver object.
-
- @discussion
-
- A resolver object is used to resolve service names to IP addresses.
-*/
-
-typedef struct DNSResolver * DNSResolverRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSResolverFlags
-
- @abstract Flags used to control resolve operations.
-
- @constant kDNSResolverFlagOneShot
- Used to indicate the resolver object should be automatically released after the first resolve.
-
- @constant kDNSResolverFlagOnlyIfUnique
- Used to indicate the resolver object should only be created if it is unique. This makes it easy for
- resolver management to be handled automatically. For example, some software needs to keep active
- resolving operations open constantly to detect things like the IP address changing (e.g. if
- displaying it to the user), but when a service goes away then comes back, a new resolver object
- will often be created, leaving two resolvers for the same name.
-
- @constant kDNSResolverFlagAutoReleaseByName
- Used to indicate the resolver object should be automatically released when the service name
- that is associated with it is no longer on the network. When a service is added to the network,
- a resolver object may be created and kept around to detect things like IP address changes. When
- the service goes off the network, this option causes the resolver associated with that service
- name to be automatically released.
-*/
-
-typedef DNSUInt32 DNSResolverFlags;
-enum
-{
- kDNSResolverFlagOneShot = ( 1 << 0 ),
- kDNSResolverFlagOnlyIfUnique = ( 1 << 1 ),
- kDNSResolverFlagAutoReleaseByName = ( 1 << 2 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSResolverEventType
-
- @abstract Type of resolver event being delivered.
-
- @constant kDNSResolverEventTypeInvalid
- Invalid event type. Here for completeness.
-
- @constant kDNSResolverEventTypeRelease
- Object is being released. No additional data is associated with this event.
-
- @constant kDNSResolverEventTypeResolved
- Name resolved.
-*/
-
-typedef long DNSResolverEventType;
-enum
-{
- kDNSResolverEventTypeInvalid = 0,
- kDNSResolverEventTypeRelease = 1,
- kDNSResolverEventTypeResolved = 10
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSResolverEventResolveData
-
- @abstract Data structure passed to callback routine when a resolve-related event occurs.
-
- @field name
- Ptr to UTF-8 string containing the resolved name of the service.
-
- @field type
- Ptr to UTF-8 string containing the resolved type of the service.
-
- @field domain
- Ptr to UTF-8 string containing the resolved domain of the service.
-
- @field interfaceID
- Network interface that received the event.
-
- @field interfaceName
- Network interface that received the event. May be empty if interface is no longer available.
-
- @field interfaceIP
- IP of network interface that received the event. May be invalid if interface is no longer available.
-
- @field address
- Network address of the service. Used to communicate with the service.
-
- @field textRecord
- Ptr to UTF-8 string containing any additional text information supplied by the service provider.
-
- @field flags
- Flags used to augment the event data.
-
- @field textRecordRaw
- Ptr to raw TXT record data. May be needed if a custom TXT record format is used.
-
- @field textRecordRawSize
- Number of bytes in raw TXT record. May be needed if a custom TXT record format is used.
-
- @field hostName
- Host name of the resolved service.
-*/
-
-typedef struct DNSResolverEventResolveData DNSResolverEventResolveData;
-struct DNSResolverEventResolveData
-{
- const char * name;
- const char * type;
- const char * domain;
- void * interfaceID;
- const char * interfaceName;
- DNSNetworkAddress interfaceIP;
- DNSNetworkAddress address;
- const char * textRecord;
- DNSResolverFlags flags;
- const void * textRecordRaw;
- DNSCount textRecordRawSize;
- const char * hostName;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSResolverEvent
-
- @abstract Data structure passed to callback routines when a resolver event occurs.
-
- @field type
- Type of event. The type determines which portion of the data union to use. Types and data union
- fields are named such as the data union field is the same as the event type. For example, a
- "resolved" event type (kDNSResolverEventTypeResolved) would refer to data union field "resolved".
-
- @field resolved
- Data associated with kDNSResolverEventTypeResolved event.
-*/
-
-typedef struct DNSResolverEvent DNSResolverEvent;
-struct DNSResolverEvent
-{
- DNSResolverEventType type;
-
- union
- {
- DNSResolverEventResolveData resolved;
-
- } data;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSResolverCallBack
-
- @abstract CallBack routine used to indicate a resolver event.
-
- @param inContext
- User-supplied context for callback (specified when browser is created).
-
- @param inRef
- Reference to resolver object generating the event.
-
- @param inStatusCode
- Status of the event.
-
- @param inEvent
- Data associated with the event.
-*/
-
-typedef void
- ( *DNSResolverCallBack )(
- void * inContext,
- DNSResolverRef inRef,
- DNSStatus inStatusCode,
- const DNSResolverEvent * inEvent );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSResolverCreate
-
- @abstract Creates a resolver object and start resolving a service name.
-
- @param inFlags
- Flags to control the resolving process.
-
- @param inName
- Ptr to UTF-8 string containing the service name to resolve (e.g. "My Printer").
-
- @param inType
- Ptr to UTF-8 string containing the service type of the service to resolve (e.g. "_printer._tcp").
-
- @param inDomain
- Ptr to UTF-8 string containing the domain of the service to resolve (e.g. "apple.com"). Use NULL
- to indicate the local domain.
-
- @param inCallBack
- CallBack routine to call when a resolver event occurs.
-
- @param inCallBackContext
- Context pointer to pass to CallBack routine when an event occurs. Not inspected by DNS Services.
-
- @param inOwner
- Reference to browser object related to this resolver. If a browser object is specified and is
- later released, this resolver object will automatically be released too. May be null.
-
- @param outRef
- Ptr to receive reference to resolver object. If the kDNSResolverFlagOnlyIfUnique flag is specified
- and there is already a resolver for the name, a NULL reference is returned in this parameter to let
- the caller know that no resolver was created. May be null.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSResolverCreate(
- DNSResolverFlags inFlags,
- const char * inName,
- const char * inType,
- const char * inDomain,
- DNSResolverCallBack inCallBack,
- void * inCallBackContext,
- DNSBrowserRef inOwner,
- DNSResolverRef * outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSResolverRelease
-
- @abstract Releases a resolver object.
-
- @param inRef
- Reference to the resolver object to release.
-
- @param inFlags
- Flags to control the release process.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSResolverRelease( DNSResolverRef inRef, DNSResolverFlags inFlags );
-
-#if 0
-#pragma mark == Browsing ==
-#endif
-
-//===========================================================================================================================
-// Browsing
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSBrowserFlags
-
- @abstract Flags used to control browser operations.
-
- @constant kDNSBrowserFlagRegistrationDomainsOnly
- Used to indicate the client is browsing only for domains to publish services. When the client wishes
- to publish a service, a domain browse operation would be started, with this flag specified, to find
- the domain used to register the service. Only valid when passed to DNSBrowserStartDomainSearch.
-
- @constant kDNSBrowserFlagAutoResolve
- Used to indicate discovered names should be automatically resolved. This eliminates the need to
- manually create a resolver to get the IP address and other information. Only valid when passed to
- DNSBrowserStartServiceSearch. When this option is used, it is important to avoid manually resolving
- names because this option causes DNS Services to automatically resolve and multiple resolvers for
- the same name will lead to unnecessary network bandwidth usage. It is also important to note that
- the notification behavior of the browser is otherwise not affected by this option so browser callback
- will still receive the same add/remove domain/service events it normally would.
-*/
-
-typedef DNSUInt32 DNSBrowserFlags;
-enum
-{
- kDNSBrowserFlagRegistrationDomainsOnly = ( 1 << 0 ),
- kDNSBrowserFlagAutoResolve = ( 1 << 1 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSBrowserEventType
-
- @abstract Type of browser event being delivered.
-
- @constant kDNSBrowserEventTypeInvalid
- Invalid event type. Here for completeness.
-
- @constant kDNSBrowserEventTypeRelease
- Object is being released. No additional data is associated with this event.
-
- @constant kDNSBrowserEventTypeAddDomain
- Domain added/found.
-
- @constant kDNSBrowserEventTypeAddDefaultDomain
- Default domain added/found. This domain should be selected as the default.
-
- @constant kDNSBrowserEventTypeRemoveDomain
- Domain removed.
-
- @constant kDNSBrowserEventTypeAddService
- Service added/found.
-
- @constant kDNSBrowserEventTypeRemoveService
- Service removed.
-
- @constant kDNSBrowserEventTypeResolved
- Name resolved. This is only delivered if the kDNSBrowserFlagAutoResolve option is used with
- DNSBrowserStartServiceSearch.
-*/
-
-typedef long DNSBrowserEventType;
-enum
-{
- kDNSBrowserEventTypeInvalid = 0,
- kDNSBrowserEventTypeRelease = 1,
- kDNSBrowserEventTypeAddDomain = 10,
- kDNSBrowserEventTypeAddDefaultDomain = 11,
- kDNSBrowserEventTypeRemoveDomain = 12,
- kDNSBrowserEventTypeAddService = 20,
- kDNSBrowserEventTypeRemoveService = 21,
- kDNSBrowserEventTypeResolved = 30
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSBrowserEventDomainData
-
- @abstract Data structure referenced by callback routines when a domain-related event occurs.
-
- @field interfaceID
- Network interface that received the event.
-
- @field interfaceName
- Network interface that received the event. May be empty if interface is no longer available.
-
- @field interfaceIP
- IP of network interface that received the event. May be invalid if interface is no longer available.
-
- @field domain
- Ptr to UTF-8 string containing the domain name. NULL if no domain name is available or applicable.
-
- @field flags
- Flags used to augment the event data.
-*/
-
-typedef struct DNSBrowserEventDomainData DNSBrowserEventDomainData;
-struct DNSBrowserEventDomainData
-{
- void * interfaceID;
- const char * interfaceName;
- DNSNetworkAddress interfaceIP;
- const char * domain;
- DNSBrowserFlags flags;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSBrowserEventServiceData
-
- @abstract Data structure passed to callback routines when a service-related event occurs.
-
- @field interfaceID
- Network interface that received the event.
-
- @field interfaceName
- Network interface that received the event. May be empty if interface is no longer available.
-
- @field interfaceIP
- IP of network interface that received the event. May be invalid if interface is no longer available.
-
- @field name
- Ptr to UTF-8 string containing the service name. NULL if no service name is available or applicable.
-
- @field type
- Ptr to UTF-8 string containing the service type. NULL if no service type is available or applicable.
-
- @field domain
- Ptr to UTF-8 string containing the domain name. NULL if no domain name is available or applicable.
-
- @field flags
- Flags used to augment the event data.
-*/
-
-typedef struct DNSBrowserEventServiceData DNSBrowserEventServiceData;
-struct DNSBrowserEventServiceData
-{
- void * interfaceID;
- const char * interfaceName;
- DNSNetworkAddress interfaceIP;
- const char * name;
- const char * type;
- const char * domain;
- DNSBrowserFlags flags;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSBrowserEvent
-
- @abstract Data structure passed to callback routines when a browser event occurs.
-
- @field type
- Type of event. The type determines which portion of the data union to use. Types and data union
- fields are named such as the data union field is the same as the event type. For example, an
- "add domain" event type (kDNSBrowserEventTypeAddDomain) would refer to data union field "addDomain".
-
- @field addDomain
- Data associated with kDNSBrowserEventTypeAddDomain event.
-
- @field addDefaultDomain
- Data associated with kDNSBrowserEventTypeAddDefaultDomain event.
-
- @field removeDomain
- Data associated with kDNSBrowserEventTypeRemoveDomain event.
-
- @field addService
- Data associated with kDNSBrowserEventTypeAddService event.
-
- @field removeService
- Data associated with kDNSBrowserEventTypeRemoveService event.
-
- @field resolved
- Data associated with kDNSBrowserEventTypeResolved event.
-*/
-
-typedef struct DNSBrowserEvent DNSBrowserEvent;
-struct DNSBrowserEvent
-{
- DNSBrowserEventType type;
-
- union
- {
- DNSBrowserEventDomainData addDomain;
- DNSBrowserEventDomainData addDefaultDomain;
- DNSBrowserEventDomainData removeDomain;
- DNSBrowserEventServiceData addService;
- DNSBrowserEventServiceData removeService;
- const DNSResolverEventResolveData * resolved;
-
- } data;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSBrowserCallBack
-
- @abstract CallBack routine used to indicate a browser event.
-
- @param inContext
- User-supplied context for callback (specified when browser is created).
-
- @param inRef
- Reference to browser object generating the event.
-
- @param inStatusCode
- Status of the event.
-
- @param inEvent
- Data associated with the event.
-*/
-
-typedef void
- ( *DNSBrowserCallBack )(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSBrowserCreate
-
- @abstract Creates a browser object.
-
- @param inFlags
- Flags to control the creation process.
-
- @param inCallBack
- CallBack routine to call when a browser event occurs.
-
- @param inCallBackContext
- Context pointer to pass to CallBack routine when an event occurs. Not inspected by DNS Services.
-
- @param outRef
- Ptr to receive reference to the created browser object. May be null.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSBrowserCreate(
- DNSBrowserFlags inFlags,
- DNSBrowserCallBack inCallBack,
- void * inCallBackContext,
- DNSBrowserRef * outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSBrowserRelease
-
- @abstract Releases a browser object.
-
- @param inRef
- Reference to the browser object to release.
-
- @param inFlags
- Flags to control the release process.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSBrowserRelease( DNSBrowserRef inRef, DNSBrowserFlags inFlags );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSBrowserStartDomainSearch
-
- @abstract Starts a domain name search.
-
- @param inRef
- Reference to browser object to start the search on.
-
- @param inFlags
- Flags to control the search process.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSBrowserStartDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSBrowserStopDomainSearch
-
- @abstract Stops a domain name search.
-
- @param inRef
- Reference to browser object to stop the search on.
-
- @param inFlags
- Flags to control the stopping process.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSBrowserStopDomainSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSBrowserStartServiceSearch
-
- @abstract Starts a service search.
-
- @param inRef
- Reference to browser object to start the search on.
-
- @param inFlags
- Flags to control the search process.
-
- @param inType
- Ptr to UTF-8 string containing the service type to search for (e.g. "_printer._tcp").
-
- @param inDomain
- Ptr to UTF-8 string containing the domain to search in (e.g. "apple.com"). Use NULL to indicate
- the local domain.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSBrowserStartServiceSearch(
- DNSBrowserRef inRef,
- DNSBrowserFlags inFlags,
- const char * inType,
- const char * inDomain );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSBrowserStopServiceSearch
-
- @abstract Stops a service search.
-
- @param inRef
- Reference to browser object to stop the search on.
-
- @param inFlags
- Flags to control the stopping process.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSBrowserStopServiceSearch( DNSBrowserRef inRef, DNSBrowserFlags inFlags );
-
-#if 0
-#pragma mark == Registration ==
-#endif
-
-//===========================================================================================================================
-// Registration
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSRegistrationRef
-
- @abstract Reference to a DNS registration object.
-*/
-
-typedef struct DNSRegistration * DNSRegistrationRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSRegistrationRecordRef
-
- @abstract Reference to a DNS record object.
-*/
-
-typedef struct DNSRegistrationRecord * DNSRegistrationRecordRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSRegistrationFlags
-
- @abstract Flags used to control registration operations.
-
- @constant kDNSRegistrationFlagPreFormattedTextRecord
- Text record is pre-formatted and should be used directly without interpretation.
-
- @constant kDNSRegistrationFlagAutoRenameOnConflict
- Automatically uniquely rename and re-register the service when a name conflict occurs.
-*/
-
-typedef DNSUInt32 DNSRegistrationFlags;
-enum
-{
- kDNSRegistrationFlagPreFormattedTextRecord = ( 1 << 0 ),
- kDNSRegistrationFlagAutoRenameOnConflict = ( 1 << 1 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSRecordFlags
-
- @abstract Flags used to control record operations.
-*/
-
-typedef DNSUInt32 DNSRecordFlags;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSRegistrationEventType
-
- @abstract Type of registration event being delivered.
-
- @constant kDNSResolverEventTypeInvalid
- Invalid event type. Here for completeness.
-
- @constant kDNSRegistrationEventTypeRelease
- Object is being released. No additional data is associated with this event.
-
- @constant kDNSRegistrationEventTypeRegistered
- Name has been successfully registered.
-
- @constant kDNSRegistrationEventTypeNameCollision
- Name collision. The registration is no longer valid. A new registration must be created if needed.
-*/
-
-typedef long DNSRegistrationEventType;
-enum
-{
- kDNSRegistrationEventTypeInvalid = 0,
- kDNSRegistrationEventTypeRelease = 1,
- kDNSRegistrationEventTypeRegistered = 10,
- kDNSRegistrationEventTypeNameCollision = 11
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct DNSRegistrationEvent
-
- @abstract Data structure passed to callback routines when a registration event occurs.
-
- @field type
- Type of event. The type determines which portion of the data union to use. Types and data union
- fields are named such as the data union field is the same as the event type.
-
- @field reserved
- Reserved for future use.
-*/
-
-typedef struct DNSRegistrationEvent DNSRegistrationEvent;
-struct DNSRegistrationEvent
-{
- DNSRegistrationEventType type;
-
- union
- {
- DNSUInt32 reserved;
-
- } data;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSRegistrationCallBack
-
- @abstract CallBack routine used to indicate a registration event.
-
- @param inContext
- User-supplied context for callback (specified when registration is created).
-
- @param inRef
- Reference to registration object generating the event.
-
- @param inStatusCode
- Status of the event.
-
- @param inEvent
- Data associated with the event.
-*/
-
-typedef void
- ( *DNSRegistrationCallBack )(
- void * inContext,
- DNSRegistrationRef inRef,
- DNSStatus inStatusCode,
- const DNSRegistrationEvent * inEvent );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSRegistrationCreate
-
- @abstract Creates a registration object and publish the registration.
-
- @param inFlags
- Flags to control the registration process.
-
- @param inName
- Ptr to UTF-8 string containing the service name to register (e.g. "My Printer").
-
- @param inType
- Ptr to UTF-8 string containing the service type of the service to registration (e.g. "_printer._tcp").
-
- @param inDomain
- Ptr to UTF-8 string containing the domain of the service to register (e.g. "apple.com"). Use NULL
- to indicate the local domain.
-
- @param inPort
- TCP/UDP port where the service is being offered (e.g. 80 for an HTTP service).
-
- @param inTextRecord
- Ptr to UTF-8 string containing any additional text to provide when the service is resolved.
-
- @param inTextRecordSize
- Size to text record.
-
- @param inHost
- Name of the host to associate with the registration. Use NULL to use the default host name.
-
- @field inInterfaceName
- Name of an interface to restrict service registration to. Use NULL to register service on all interfaces.
-
- @param inCallBack
- CallBack routine to call when a registration event occurs.
-
- @param inCallBackContext
- Context pointer to pass to CallBack routine when an event occurs. Not inspected by DNS Services.
-
- @param outRef
- Ptr to receive reference to registration object. May be null.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSRegistrationCreate(
- DNSRegistrationFlags inFlags,
- const char * inName,
- const char * inType,
- const char * inDomain,
- DNSPort inPort,
- const void * inTextRecord,
- DNSCount inTextRecordSize,
- const char * inHost,
- const char * inInterfaceName,
- DNSRegistrationCallBack inCallBack,
- void * inCallBackContext,
- DNSRegistrationRef * outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSNoSuchServiceRegistrationCreate
-
- @abstract Creates a registration object and publish the registration to assert non-existence of a particular service.
-
- @param inFlags
- Flags to control the registration process.
-
- @param inName
- Ptr to UTF-8 string containing the service name to register (e.g. "My Printer").
-
- @param inType
- Ptr to UTF-8 string containing the service type of the service to registration (e.g. "_printer._tcp").
-
- @param inDomain
- Ptr to UTF-8 string containing the domain of the service to register (e.g. "apple.com"). Use NULL
- to indicate the local domain.
-
- @field inInterfaceName
- Name of an interface to restrict service registration to. Use NULL to register service on all interfaces.
-
- @param inCallBack
- CallBack routine to call when a registration event occurs.
-
- @param inCallBackContext
- Context pointer to pass to CallBack routine when an event occurs. Not inspected by DNS Services.
-
- @param outRef
- Ptr to receive reference to registration object. May be null.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSNoSuchServiceRegistrationCreate(
- DNSRegistrationFlags inFlags,
- const char * inName,
- const char * inType,
- const char * inDomain,
- const char * inInterfaceName,
- DNSRegistrationCallBack inCallBack,
- void * inCallBackContext,
- DNSRegistrationRef * outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSRegistrationRelease
-
- @abstract Releases a registration object.
-
- @param inRef
- Reference to the registration object to release.
-
- @param inFlags
- Flags to control the release process.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSRegistrationRelease( DNSRegistrationRef inRef, DNSRegistrationFlags inFlags );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSRegistrationUpdate
-
- @abstract Updates an individual record for a registration.
-
- @param inRef
- Reference to the registration object to update.
-
- @param inRecord
- Record to update. Use NULL for the standard TXT record.
-
- @param inData
- New record data.
-
- @param inSize
- Size of new record data.
-
- @param inNewTTL
- New time-to-live (TTL) in seconds for the updated data (e.g. 120 for 2 minutes).
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSRegistrationUpdate(
- DNSRegistrationRef inRef,
- DNSRecordFlags inFlags,
- DNSRegistrationRecordRef inRecord,
- const void * inData,
- DNSCount inSize,
- DNSUInt32 inNewTTL );
-
-#if 0
-#pragma mark == Domain Registration ==
-#endif
-
-//===========================================================================================================================
-// Domain Registration
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSDomainRegistrationRef
-
- @abstract Reference to a DNS registration object.
-*/
-
-typedef struct DNSDomainRegistration * DNSDomainRegistrationRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSDomainRegistrationFlags
-
- @abstract Flags used to control registration operations.
-*/
-
-typedef DNSUInt32 DNSDomainRegistrationFlags;
-enum
-{
- kDNSDomainRegistrationFlagNone = 0
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSDomainRegistrationType
-
- @abstract Type of domain registration.
-
- @constant kDNSDomainRegistrationTypeBrowse
- Registration for domain browsing.
-
- @constant kDNSDomainRegistrationTypeBrowseDefault
- Registration for the domain browsing domain.
-
- @constant kDNSDomainRegistrationTypeRegistration
- Registration for domain registration.
-
- @constant kDNSDomainRegistrationTypeRegistrationDefault
- Registration for the domain registration domain.
-*/
-
-typedef DNSUInt32 DNSDomainRegistrationType;
-enum
-{
- kDNSDomainRegistrationTypeBrowse = 0,
- kDNSDomainRegistrationTypeBrowseDefault = 1,
- kDNSDomainRegistrationTypeRegistration = 2,
- kDNSDomainRegistrationTypeRegistrationDefault = 3,
-
- kDNSDomainRegistrationTypeMax = 4
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSDomainRegistrationCreate
-
- @abstract Creates a domain registration object and publish the domain.
-
- @param inFlags
- Flags to control the registration process.
-
- @param inName
- Ptr to string containing the domain name to register (e.g. "apple.com").
-
- @param inType
- Type of domain registration.
-
- @param outRef
- Ptr to receive reference to domain registration object. May be null.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSDomainRegistrationCreate(
- DNSDomainRegistrationFlags inFlags,
- const char * inName,
- DNSDomainRegistrationType inType,
- DNSDomainRegistrationRef * outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSDomainRegistrationRelease
-
- @abstract Releases a domain registration object.
-
- @param inRef
- Reference to the domain registration object to release.
-
- @param inFlags
- Flags to control the release process.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSDomainRegistrationRelease( DNSDomainRegistrationRef inRef, DNSDomainRegistrationFlags inFlags );
-
-#if 0
-#pragma mark == Host Registration ==
-#endif
-
-//===========================================================================================================================
-// Host Registration
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DNSHostRegistrationRef
-
- @abstract Reference to a DNS host registration object.
-*/
-
-typedef struct DNSHostRegistration * DNSHostRegistrationRef;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DNSHostRegistrationFlags
-
- @abstract Flags used to control registration operations.
-
- @constant kDNSHostRegistrationFlagOnlyIfNotFound
- Only creates the object and registers the host if it was not already found in the list.
-
- @constant kDNSHostRegistrationFlagAutoRenameOnConflict
- Automatically uniquely rename and re-register the host when a name conflict occurs.
-
-*/
-
-typedef DNSUInt32 DNSHostRegistrationFlags;
-enum
-{
- kDNSHostRegistrationFlagNone = 0,
- kDNSHostRegistrationFlagOnlyIfNotFound = ( 1 << 0 ),
- kDNSHostRegistrationFlagAutoRenameOnConflict = ( 1 << 1 )
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSHostRegistrationCallBack
-
- @abstract CallBack routine used to indicate a host registration event.
-
- @param inContext
- User-supplied context for callback (specified when browser is created).
-
- @param inRef
- Reference to resolver object generating the event.
-
- @param inStatusCode
- Status of the event.
-
- @param inData
- Data associated with the event.
-*/
-
-typedef void
- ( *DNSHostRegistrationCallBack )(
- void * inContext,
- DNSHostRegistrationRef inRef,
- DNSStatus inStatusCode,
- void * inData );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSHostRegistrationCreate
-
- @abstract Creates a host registration object and publishes the host.
-
- @param inFlags
- Flags to control the registration process.
-
- @param inName
- Name of the host to register (e.g. "My Web Server").
-
- @param inDomain
- Domain of the host to register (e.g. "apple.com"). Use NULL to indicate the local domain.
-
- @param inAddr
- IP address of host to register.
-
- @field inInterfaceName
- Name of an interface to restrict registration to. Use NULL to register on all interfaces.
-
- @param inCallBack
- CallBack routine to call when an event occurs.
-
- @param inCallBackContext
- Context pointer to pass to callback routine when an event occurs. Not inspected by DNS Services.
-
- @param outRef
- Ptr to receive reference to host registration object. May be null.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSHostRegistrationCreate(
- DNSHostRegistrationFlags inFlags,
- const char * inName,
- const char * inDomain,
- const DNSNetworkAddress * inAddr,
- const char * inInterfaceName,
- DNSHostRegistrationCallBack inCallBack,
- void * inCallBackContext,
- DNSHostRegistrationRef * outRef );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSHostRegistrationRelease
-
- @abstract Releases a host registration object.
-
- @param inRef
- Reference to the host registration object to release.
-
- @param inFlags
- Flags to control the release process.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSHostRegistrationRelease( DNSHostRegistrationRef inRef, DNSHostRegistrationFlags inFlags );
-
-#if 0
-#pragma mark == Utilities ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined kDNSTextRecordNoValue
-
- @abstract Value to use when no value is desired for a name/value pair (e.g. "color" instead of "color=").
-*/
-
-#define kDNSTextRecordNoValue ( (const void *) -1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined kDNSTextRecordStringNoValue
-
- @abstract Value to use when no value is desired for a name/value pair (e.g. "color" instead of "color=").
-*/
-
-#define kDNSTextRecordStringNoValue ( (const char *) -1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined kDNSTextRecordNoValue
-
- @abstract Size value to use when no value is desired for a name/value pair (e.g. "color" instead of "color=").
-*/
-
-#define kDNSTextRecordNoSize ( (size_t) -1 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSDynamicTextRecordBuildEscaped
-
- @abstract Builds a TXT record from a string with \001 escape sequences to separate strings within the TXT record.
-
- @param inFormat C-string TXT record with \001 escape sequences as record separators.
- @param outTextRecord Receives a ptr to a built TXT record. Must free with DNSDynamicTextRecordRelease.
- @param outSize Receive actual size of the built TXT record. Use NULL if you don't need the size.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-
- @discussion
-
- A DNS TXT record consists of a packed array of length-prefixed strings with each string being up to 255 characters.
- To allow this to be described with a null-terminated C-string, a special escape sequence of \001 is used to separate
- individual character strings within the C-string.
-
- For example, to represent the following 3 segments "test1=1", "test2=2", and "test3=3", you would use the following:
-
- DNSUInt8 * txt;
- size_t size;
-
- txt = NULL;
-
- err = DNSDynamicTextRecordBuildEscaped( "test1=1\001test2=2\001test3=3", &txt, &size );
- require_noerr( err, exit );
-
- ... use text record
-
-exit:
- DNSDynamicTextRecordRelease( txt );
-*/
-
-DNSStatus DNSDynamicTextRecordBuildEscaped( const char *inFormat, void *outTextRecord, size_t *outSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSDynamicTextRecordAppendCString
-
- @abstract Appends a name/value pair with the value being a C-string to a dynamic DNS TXT record data section.
-
- @param ioTxt Input: Ptr to a ptr to TXT record to append to.
- Output: Receives newly allocated ptr to the new TXT record.
- Note: Use a ptr to NULL the first time this is called.
-
- @param ioTxtSize Input: Ptr to size of existing TXT record.
- Output: Receives new size of TXT record.
-
- @param inName C-string name in the name/value pair (e.g. "path" for HTTP).
-
- @param inValue C-string value in the name/value pair (e.g. "/index.html for HTTP).
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-
- @discussion
-
- This can be used to easily build dynamically-resized TXT records containing multiple name/value pairs of C-strings.
- For example, the following adds "name=Ryknow", "age=30", and "job=Musician":
-
- DNSUInt8 * txt;
- size_t size;
-
- txt = NULL;
- size = 0;
-
- err = DNSDynamicTextRecordAppendCString( &txt, &size, "name", "Ryknow" );
- require_noerr( err, exit );
-
- err = DNSDynamicTextRecordAppendCString( &txt, &size, "age", "30" );
- require_noerr( err, exit );
-
- err = DNSDynamicTextRecordAppendCString( &txt, &size, "job", "Musician" );
- require_noerr( err, exit );
-
- ... use text record
-
-exit:
- DNSDynamicTextRecordRelease( txt );
-*/
-
-DNSStatus DNSDynamicTextRecordAppendCString( void *ioTxt, size_t *ioTxtSize, const char *inName, const char *inValue );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSDynamicTextRecordAppendData
-
- @abstract Appends a name/value pair to a dynamic DNS TXT record data section.
-
- @param ioTxt Input: Ptr to a ptr to TXT record to append to.
- Output: Receives newly allocated ptr to the new TXT record.
- Note: Use a ptr to NULL the first time this is called.
-
- @param ioTxtSize Input: Ptr to size of existing TXT record.
- Output: Receives new size of TXT record.
-
- @param inName C-string name in the name/value pair (e.g. "path" for HTTP).
-
- @param inValue Value data to associate with the name. Use kDNSTextRecordNoValue for no value.
-
- @param inValueSize Size of value data. Use kDNSTextRecordNoSize for no value.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSDynamicTextRecordAppendData(
- void * ioTxt,
- size_t * ioTxtSize,
- const char * inName,
- const void * inValue,
- size_t inValueSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSDynamicTextRecordRelease
-
- @abstract Releases a dynamically allocated TXT record.
-
- @param inTxt Dynamic TXT record to release.
-
- @discussion
-
- This API may only be used with TXT records generated with DNSDynamicTextRecordAppendCString and
- DNSDynamicTextRecordAppendData.
-*/
-
-void DNSDynamicTextRecordRelease( void *inTxt );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSTextRecordAppendCString
-
- @abstract Appends a name/value pair with the value being a C-string to DNS TXT record data section.
-
- @param inTxt TXT record to append to.
- @param inTxtSize Size of existing TXT record.
- @param inTxtMaxSize Maximum size of TXT record (i.e. size of buffer).
- @param inName C-string name in the name/value pair (e.g. "path" for HTTP).
- @param inValue C-string value in the name/value pair (e.g. "/index.html for HTTP).
- @param outTxtSize Receives resulting size of TXT record. Pass NULL if not needed.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-
- @discussion
-
- This can be used to easily build TXT records containing multiple name/value pairs of C-strings. For example, the
- following adds "name=Ryknow", "age=30", and "job=Musician":
-
- DNSUInt8 txt[ 256 ];
- size_t size;
-
- size = 0;
-
- err = DNSTextRecordAppendCString( txt, size, sizeof( txt ), "name", "Ryknow", &size );
- require_noerr( err, exit );
-
- err = DNSTextRecordAppendCString( txt, size, sizeof( txt ), "age", "30", &size );
- require_noerr( err, exit );
-
- err = DNSTextRecordAppendCString( txt, size, sizeof( txt ), "job", "Musician", &size );
- require_noerr( err, exit );
-*/
-
-DNSStatus
- DNSTextRecordAppendCString(
- void * inTxt,
- size_t inTxtSize,
- size_t inTxtMaxSize,
- const char * inName,
- const char * inValue,
- size_t * outTxtSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSTextRecordAppendData
-
- @abstract Appends a name/value pair to a DNS TXT record data section.
-
- @param inTxt TXT record to append to.
- @param inTxtSize Size of existing TXT record.
- @param inTxtMaxSize Maximum size of TXT record (i.e. size of buffer).
- @param inName C-string name in the name/value pair (e.g. "path" for HTTP).
- @param inValue Value data to associate with the name. Use kDNSTextRecordNoValue for no value.
- @param inValueSize Size of value data. Use kDNSTextRecordNoSize for no value.
- @param outTxtSize Receives resulting size of TXT record. Pass NULL if not needed.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus
- DNSTextRecordAppendData(
- void * inTxt,
- size_t inTxtSize,
- size_t inTxtMaxSize,
- const char * inName,
- const void * inValue,
- size_t inValueSize,
- size_t * outTxtSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSTextRecordEscape
-
- @abstract Converts a raw TXT record into a single, null-terminated string with \001 to delimit records.
-
- @param inTextRecord Raw TXT record to escape.
- @param inTextSize Number of bytes in the raw TXT record to escape.
- @param outEscapedString Receives ptr to escaped, \001-delimited, null-terminated string.
-
- @result Error code indicating failure reason or kDNSNoErr if successful.
-*/
-
-DNSStatus DNSTextRecordEscape( const void *inTextRecord, size_t inTextSize, char **outEscapedString );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSNameValidate
-
- @abstract Validates a DNS name for correctness.
-
- @param inName C-string DNS name to validate.
-
- @result Error code indicating failure reason or kDNSNoErr if valid.
-*/
-
-DNSStatus DNSNameValidate( const char *inName );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSServiceTypeValidate
-
- @abstract Validates a service type for correctness.
-
- @param inServiceType C-string service type to validate.
-
- @result Error code indicating failure reason or kDNSNoErr if valid.
-*/
-
-DNSStatus DNSServiceTypeValidate( const char *inServiceType );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DNSTextRecordValidate
-
- @abstract Validates a text record for correctness and optionally builds the TXT reocrd, and returns the actual size.
-
- @param inText C-string TXT record to validate. Use \001 escape sequence as record separator.
- @param inMaxSize Maximum size of the TXT record. Use a large number if a max size is not appropriate.
- @param outRecord Buffer to receive built TXT record. Use NULL if you don't need a built TXT record.
- @param outActualSize Ptr to receive actual size of TXT record. Use NULL if you don't need the actual size.
-
- @result Error code indicating failure reason or kDNSNoErr if valid.
-
- @discussion
-
- A DNS TXT record consists of a packed array of length-prefixed strings with each string being up to 255 characters.
- To allow this to be described with a null-terminated C-string, a special escape sequence of \001 is used to separate
- individual character strings within the C-string.
-
- For example, to represent the following 3 segments "test1=1", "test2=2", and "test3=3", you would use the following:
-
- "test1=1\001test2=2\001test3=3"
-*/
-
-DNSStatus DNSTextRecordValidate( const char *inText, size_t inMaxSize, void *outRecord, size_t *outActualSize );
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif // __DNS_SERVICES__
+++ /dev/null
-/*
- * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: DebugServices.c,v $
-Revision 1.5 2004/09/17 01:08:57 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.4 2004/04/15 08:59:08 bradley
-Removed deprecated debug and log levels and replaced them with modern equivalents.
-
-Revision 1.3 2004/04/08 09:29:55 bradley
-Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
-hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
-Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
-
-Revision 1.2 2004/03/07 05:59:34 bradley
-Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
-
-Revision 1.1 2004/01/30 02:27:30 bradley
-Debugging support for various platforms.
-
-
- To Do:
-
- - Use StackWalk on Windows to optionally print stack frames.
-*/
-
-#if 0
-#pragma mark == Includes ==
-#endif
-
-//===========================================================================================================================
-// Includes
-//===========================================================================================================================
-
-#if( !KERNEL )
- #include <ctype.h>
- #include <stdio.h>
- #include <string.h>
-#endif
-
-#include "CommonServices.h"
-
-#include "DebugServices.h"
-
-#if( DEBUG )
-
-#if( TARGET_OS_VXWORKS )
- #include "intLib.h"
-#endif
-
-#if( TARGET_OS_WIN32 )
- #include <time.h>
-
- #if( !TARGET_OS_WINDOWS_CE )
- #include <fcntl.h>
- #include <io.h>
- #endif
-#endif
-
-#if( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL )
- #include <IOKit/IOLib.h>
-#endif
-
-// If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h.
-
-#if( defined( MDNS_DEBUGMSGS ) )
- #include "mDNSEmbeddedAPI.h"
-#endif
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//===========================================================================================================================
-// Macros
-//===========================================================================================================================
-
-#define DebugIsPrint( C ) ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) )
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize );
-
-// fprintf
-
-#if( DEBUG_FPRINTF_ENABLED )
- static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename );
- static void DebugFPrintFPrint( char *inData, size_t inSize );
-#endif
-
-// iDebug (Mac OS X user and kernel)
-
-#if( DEBUG_IDEBUG_ENABLED )
- static OSStatus DebugiDebugInit( void );
- static void DebugiDebugPrint( char *inData, size_t inSize );
-#endif
-
-// kprintf (Mac OS X Kernel)
-
-#if( DEBUG_KPRINTF_ENABLED )
- static void DebugKPrintFPrint( char *inData, size_t inSize );
-#endif
-
-// Mac OS X IOLog (Mac OS X Kernel)
-
-#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
- static void DebugMacOSXIOLogPrint( char *inData, size_t inSize );
-#endif
-
-// Mac OS X Log
-
-#if( TARGET_OS_MAC )
- static OSStatus DebugMacOSXLogInit( void );
- static void DebugMacOSXLogPrint( char *inData, size_t inSize );
-#endif
-
-// Windows Debugger
-
-#if( TARGET_OS_WIN32 )
- static void DebugWindowsDebuggerPrint( char *inData, size_t inSize );
-#endif
-
-// Windows Event Log
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
- static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule );
- static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize );
-#endif
-
-// DebugLib support
-
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
- static pascal void
- DebugAssertOutputHandler(
- OSType inComponentSignature,
- UInt32 inOptions,
- const char * inAssertionString,
- const char * inExceptionString,
- const char * inErrorString,
- const char * inFileName,
- long inLineNumber,
- void * inValue,
- ConstStr255Param inOutputMsg );
-#endif
-
-// Utilities
-
-static char * DebugNumVersionToString( uint32_t inVersion, char *inString );
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
- static void DebugWinEnableConsole( void );
-#endif
-
-#if( TARGET_OS_WIN32 )
- static TCHAR *
- DebugWinCharToTCharString(
- const char * inCharString,
- size_t inCharCount,
- TCHAR * outTCharString,
- size_t inTCharCountMax,
- size_t * outTCharCount );
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-// Private Globals
-//===========================================================================================================================
-
-#if( TARGET_OS_VXWORKS )
- // TCP States for inetstatShow.
-
- extern char ** pTcpstates; // defined in tcpLib.c
-
- const char * kDebugTCPStates[] =
- {
- "(0) TCPS_CLOSED",
- "(1) TCPS_LISTEN",
- "(2) TCPS_SYN_SENT",
- "(3) TCPS_SYN_RECEIVED",
- "(4) TCPS_ESTABLISHED",
- "(5) TCPS_CLOSE_WAIT",
- "(6) TCPS_FIN_WAIT_1",
- "(7) TCPS_CLOSING",
- "(8) TCPS_LAST_ACK",
- "(9) TCPS_FIN_WAIT_2",
- "(10) TCPS_TIME_WAIT",
- };
-#endif
-
-// General
-
-static bool gDebugInitialized = false;
-static DebugOutputType gDebugOutputType = kDebugOutputTypeNone;
-static DebugLevel gDebugPrintLevelMin = kDebugLevelInfo;
-static DebugLevel gDebugPrintLevelMax = kDebugLevelMax;
-static DebugLevel gDebugBreakLevel = kDebugLevelAssert;
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
- static DebugAssertOutputHandlerUPP gDebugAssertOutputHandlerUPP = NULL;
-#endif
-
-// Custom
-
-static DebugOutputFunctionPtr gDebugCustomOutputFunction = NULL;
-static void * gDebugCustomOutputContext = NULL;
-
-// fprintf
-
-#if( DEBUG_FPRINTF_ENABLED )
- static FILE * gDebugFPrintFFile = NULL;
-#endif
-
-// MacOSXLog
-
-#if( TARGET_OS_MAC )
- typedef int ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... );
-
- static DebugMacOSXLogFunctionPtr gDebugMacOSXLogFunction = NULL;
-#endif
-
-// WindowsEventLog
-
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
- static HANDLE gDebugWindowsEventLogEventSource = NULL;
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == General ==
-#endif
-
-//===========================================================================================================================
-// DebugInitialize
-//===========================================================================================================================
-
-DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... )
-{
- OSStatus err;
- DebugOutputType type;
- va_list args;
-
- va_start( args, inType );
-
-#if( TARGET_OS_VXWORKS )
- // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
-
- if( !pTcpstates )
- {
- pTcpstates = (char **) kDebugTCPStates;
- }
-#endif
-
- // Set up DebugLib stuff (if building with Debugging.h).
-
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
- if( !gDebugAssertOutputHandlerUPP )
- {
- gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler );
- check( gDebugAssertOutputHandlerUPP );
- if( gDebugAssertOutputHandlerUPP )
- {
- InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP );
- }
- }
-#endif
-
- // Pre-process meta-output kind to pick an appropriate output kind for the platform.
-
- type = inType;
- if( type == kDebugOutputTypeMetaConsole )
- {
- #if( TARGET_OS_MAC )
- type = kDebugOutputTypeMacOSXLog;
- #elif( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
- #if( DEBUG_FPRINTF_ENABLED )
- type = kDebugOutputTypeFPrintF;
- #else
- type = kDebugOutputTypeWindowsDebugger;
- #endif
- #elif( TARGET_API_MAC_OSX_KERNEL )
- #if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
- type = kDebugOutputTypeMacOSXIOLog;
- #elif( DEBUG_IDEBUG_ENABLED )
- type = kDebugOutputTypeiDebug;
- #elif( DEBUG_KPRINTF_ENABLED )
- type = kDebugOutputTypeKPrintF;
- #endif
- #elif( TARGET_OS_VXWORKS )
- #if( DEBUG_FPRINTF_ENABLED )
- type = kDebugOutputTypeFPrintF;
- #else
- #error target is VxWorks, but fprintf output is disabled
- #endif
- #else
- #if( DEBUG_FPRINTF_ENABLED )
- type = kDebugOutputTypeFPrintF;
- #endif
- #endif
- }
-
- // Process output kind.
-
- gDebugOutputType = type;
- switch( type )
- {
- case kDebugOutputTypeNone:
- err = kNoErr;
- break;
-
- case kDebugOutputTypeCustom:
- gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr );
- gDebugCustomOutputContext = va_arg( args, void * );
- err = kNoErr;
- break;
-
-#if( DEBUG_FPRINTF_ENABLED )
- case kDebugOutputTypeFPrintF:
- if( inType == kDebugOutputTypeMetaConsole )
- {
- err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL );
- }
- else
- {
- DebugOutputTypeFlags flags;
- const char * filename;
-
- flags = (DebugOutputTypeFlags) va_arg( args, unsigned int );
- if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile )
- {
- filename = va_arg( args, const char * );
- }
- else
- {
- filename = NULL;
- }
- err = DebugFPrintFInit( flags, filename );
- }
- break;
-#endif
-
-#if( DEBUG_IDEBUG_ENABLED )
- case kDebugOutputTypeiDebug:
- err = DebugiDebugInit();
- break;
-#endif
-
-#if( DEBUG_KPRINTF_ENABLED )
- case kDebugOutputTypeKPrintF:
- err = kNoErr;
- break;
-#endif
-
-#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
- case kDebugOutputTypeMacOSXIOLog:
- err = kNoErr;
- break;
-#endif
-
-#if( TARGET_OS_MAC )
- case kDebugOutputTypeMacOSXLog:
- err = DebugMacOSXLogInit();
- break;
-#endif
-
-#if( TARGET_OS_WIN32 )
- case kDebugOutputTypeWindowsDebugger:
- err = kNoErr;
- break;
-#endif
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
- case kDebugOutputTypeWindowsEventLog:
- {
- const char * name;
- HMODULE module;
-
- name = va_arg( args, const char * );
- module = va_arg( args, HMODULE );
- err = DebugWindowsEventLogInit( name, module );
- }
- break;
-#endif
-
- default:
- err = kParamErr;
- goto exit;
- }
- gDebugInitialized = true;
-
-exit:
- va_end( args );
- return( err );
-}
-
-//===========================================================================================================================
-// DebugFinalize
-//===========================================================================================================================
-
-DEBUG_EXPORT void DebugFinalize( void )
-{
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
- check( gDebugAssertOutputHandlerUPP );
- if( gDebugAssertOutputHandlerUPP )
- {
- InstallDebugAssertOutputHandler( NULL );
- DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP );
- gDebugAssertOutputHandlerUPP = NULL;
- }
-#endif
-}
-
-//===========================================================================================================================
-// DebugGetProperty
-//===========================================================================================================================
-
-DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... )
-{
- OSStatus err;
- va_list args;
- DebugLevel * level;
-
- va_start( args, inTag );
- switch( inTag )
- {
- case kDebugPropertyTagPrintLevelMin:
- level = va_arg( args, DebugLevel * );
- *level = gDebugPrintLevelMin;
- err = kNoErr;
- break;
-
- case kDebugPropertyTagPrintLevelMax:
- level = va_arg( args, DebugLevel * );
- *level = gDebugPrintLevelMax;
- err = kNoErr;
- break;
-
- case kDebugPropertyTagBreakLevel:
- level = va_arg( args, DebugLevel * );
- *level = gDebugBreakLevel;
- err = kNoErr;
- break;
-
- default:
- err = kUnsupportedErr;
- break;
- }
- va_end( args );
- return( err );
-}
-
-//===========================================================================================================================
-// DebugSetProperty
-//===========================================================================================================================
-
-DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... )
-{
- OSStatus err;
- va_list args;
- DebugLevel level;
-
- va_start( args, inTag );
- switch( inTag )
- {
- case kDebugPropertyTagPrintLevelMin:
- level = va_arg( args, DebugLevel );
- gDebugPrintLevelMin = level;
- err = kNoErr;
- break;
-
- case kDebugPropertyTagPrintLevelMax:
- level = va_arg( args, DebugLevel );
- gDebugPrintLevelMax = level;
- err = kNoErr;
- break;
-
- case kDebugPropertyTagBreakLevel:
- level = va_arg( args, DebugLevel );
- gDebugBreakLevel = level;
- err = kNoErr;
- break;
-
- default:
- err = kUnsupportedErr;
- break;
- }
- va_end( args );
- return( err );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Output ==
-#endif
-
-//===========================================================================================================================
-// DebugPrintF
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... )
-{
- va_list args;
- size_t n;
-
- // Skip if the level is not in the enabled range..
-
- if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
- {
- n = 0;
- goto exit;
- }
-
- va_start( args, inFormat );
- n = DebugPrintFVAList( inLevel, inFormat, args );
- va_end( args );
-
-exit:
- return( n );
-}
-
-//===========================================================================================================================
-// DebugPrintFVAList
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs )
-{
- size_t n;
- char buffer[ 512 ];
-
- // Skip if the level is not in the enabled range..
-
- if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
- {
- n = 0;
- goto exit;
- }
-
- n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs );
- DebugPrint( inLevel, buffer, (size_t) n );
-
-exit:
- return( n );
-}
-
-//===========================================================================================================================
-// DebugPrint
-//===========================================================================================================================
-
-static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
-{
- OSStatus err;
-
- // Skip if the level is not in the enabled range..
-
- if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
- {
- err = kRangeErr;
- goto exit;
- }
-
- // Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available).
-
- if( DebugTaskLevel() & kDebugInterruptLevelMask )
- {
- #if( TARGET_OS_VXWORKS )
- logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
- #endif
-
- err = kExecutionStateErr;
- goto exit;
- }
-
- // Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage).
-
- if( !gDebugInitialized )
- {
- debug_initialize( kDebugOutputTypeMetaConsole );
- }
-
- // Print based on the current output type.
-
- switch( gDebugOutputType )
- {
- case kDebugOutputTypeNone:
- break;
-
- case kDebugOutputTypeCustom:
- if( gDebugCustomOutputFunction )
- {
- gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext );
- }
- break;
-
-#if( DEBUG_FPRINTF_ENABLED )
- case kDebugOutputTypeFPrintF:
- DebugFPrintFPrint( inData, inSize );
- break;
-#endif
-
-#if( DEBUG_IDEBUG_ENABLED )
- case kDebugOutputTypeiDebug:
- DebugiDebugPrint( inData, inSize );
- break;
-#endif
-
-#if( DEBUG_KPRINTF_ENABLED )
- case kDebugOutputTypeKPrintF:
- DebugKPrintFPrint( inData, inSize );
- break;
-#endif
-
-#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
- case kDebugOutputTypeMacOSXIOLog:
- DebugMacOSXIOLogPrint( inData, inSize );
- break;
-#endif
-
-#if( TARGET_OS_MAC )
- case kDebugOutputTypeMacOSXLog:
- DebugMacOSXLogPrint( inData, inSize );
- break;
-#endif
-
-#if( TARGET_OS_WIN32 )
- case kDebugOutputTypeWindowsDebugger:
- DebugWindowsDebuggerPrint( inData, inSize );
- break;
-#endif
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
- case kDebugOutputTypeWindowsEventLog:
- DebugWindowsEventLogPrint( inLevel, inData, inSize );
- break;
-#endif
-
- default:
- break;
- }
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DebugPrintAssert
-//
-// Warning: This routine relies on several of the strings being string constants that will exist forever because the
-// underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based
-// pointer variables (e.g. local strings). The debug macros that invoke this function only use constant
-// constant strings, but if this function is invoked directly from other places, it must use constant strings.
-//===========================================================================================================================
-
-DEBUG_EXPORT void
- DebugPrintAssert(
- int_least32_t inErrorCode,
- const char * inAssertString,
- const char * inMessage,
- const char * inFilename,
- int_least32_t inLineNumber,
- const char * inFunction )
-{
- // Skip if the level is not in the enabled range..
-
- if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) )
- {
- return;
- }
-
- if( inErrorCode != 0 )
- {
- DebugPrintF(
- kDebugLevelAssert,
- "\n"
- "[ASSERT] error: %ld (%m)\n"
- "[ASSERT] where: \"%s\", line %ld, \"%s\"\n"
- "\n",
- inErrorCode, inErrorCode,
- inFilename ? inFilename : "",
- inLineNumber,
- inFunction ? inFunction : "" );
- }
- else
- {
- DebugPrintF(
- kDebugLevelAssert,
- "\n"
- "[ASSERT] assert: \"%s\" %s\n"
- "[ASSERT] where: \"%s\", line %ld, \"%s\"\n"
- "\n",
- inAssertString ? inAssertString : "",
- inMessage ? inMessage : "",
- inFilename ? inFilename : "",
- inLineNumber,
- inFunction ? inFunction : "" );
- }
-
- // Break into the debugger if enabled.
-
- #if( TARGET_OS_WIN32 )
- if( gDebugBreakLevel <= kDebugLevelAssert )
- {
- if( IsDebuggerPresent() )
- {
- DebugBreak();
- }
- }
- #endif
-}
-
-#if 0
-#pragma mark -
-#endif
-
-#if( DEBUG_FPRINTF_ENABLED )
-//===========================================================================================================================
-// DebugFPrintFInit
-//===========================================================================================================================
-
-static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename )
-{
- OSStatus err;
- DebugOutputTypeFlags typeFlags;
-
- typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask;
- if( typeFlags == kDebugOutputTypeFlagsStdOut )
- {
- #if( TARGET_OS_WIN32 )
- DebugWinEnableConsole();
- #endif
-
- gDebugFPrintFFile = stdout;
- }
- else if( typeFlags == kDebugOutputTypeFlagsStdErr )
- {
- #if( TARGET_OS_WIN32 )
- DebugWinEnableConsole();
- #endif
-
- gDebugFPrintFFile = stdout;
- }
- else if( typeFlags == kDebugOutputTypeFlagsFile )
- {
- require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr );
-
- gDebugFPrintFFile = fopen( inFilename, "a" );
- require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr );
- }
- else
- {
- err = kParamErr;
- goto exit;
- }
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DebugFPrintFPrint
-//===========================================================================================================================
-
-static void DebugFPrintFPrint( char *inData, size_t inSize )
-{
- char * p;
- char * q;
-
- // Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform.
-
- p = inData;
- q = p + inSize;
- while( p < q )
- {
- if( *p == '\r' )
- {
- *p = '\n';
- }
- ++p;
- }
-
- // Write the data and flush.
-
- if( gDebugFPrintFFile )
- {
- fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData );
- fflush( gDebugFPrintFFile );
- }
-}
-#endif // DEBUG_FPRINTF_ENABLED
-
-#if( DEBUG_IDEBUG_ENABLED )
-//===========================================================================================================================
-// DebugiDebugInit
-//===========================================================================================================================
-
-static OSStatus DebugiDebugInit( void )
-{
- OSStatus err;
-
- #if( TARGET_API_MAC_OSX_KERNEL )
-
- extern uint32_t * _giDebugReserved1;
-
- // Emulate the iDebugSetOutputType macro in iDebugServices.h.
- // Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext.
-
- if( !_giDebugReserved1 )
- {
- _giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) );
- require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr );
- }
- *_giDebugReserved1 = 0x00010000U;
- err = kNoErr;
-exit:
- #else
-
- __private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType );
-
- iDebugSetOutputTypeInternal( 0x00010000U );
- err = kNoErr;
-
- #endif
-
- return( err );
-}
-
-//===========================================================================================================================
-// DebugiDebugPrint
-//===========================================================================================================================
-
-static void DebugiDebugPrint( char *inData, size_t inSize )
-{
- #if( TARGET_API_MAC_OSX_KERNEL )
-
- // Locally declared here so we do not need to include iDebugKext.h.
- // Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the
- // KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present).
- // _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present.
-
- typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
-
- extern iDebugLogFunctionPtr _giDebugLogInternal;
-
- if( _giDebugLogInternal )
- {
- _giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
- }
-
- #else
-
- __private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
-
- iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
-
- #endif
-}
-#endif
-
-#if( DEBUG_KPRINTF_ENABLED )
-//===========================================================================================================================
-// DebugKPrintFPrint
-//===========================================================================================================================
-
-static void DebugKPrintFPrint( char *inData, size_t inSize )
-{
- extern void kprintf( const char *inFormat, ... );
-
- kprintf( "%.*s", (int) inSize, inData );
-}
-#endif
-
-#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
-//===========================================================================================================================
-// DebugMacOSXIOLogPrint
-//===========================================================================================================================
-
-static void DebugMacOSXIOLogPrint( char *inData, size_t inSize )
-{
- extern void IOLog( const char *inFormat, ... );
-
- IOLog( "%.*s", (int) inSize, inData );
-}
-#endif
-
-#if( TARGET_OS_MAC )
-//===========================================================================================================================
-// DebugMacOSXLogInit
-//===========================================================================================================================
-
-static OSStatus DebugMacOSXLogInit( void )
-{
- OSStatus err;
- CFStringRef path;
- CFURLRef url;
- CFBundleRef bundle;
- CFStringRef functionName;
- void * functionPtr;
-
- bundle = NULL;
-
- // Create a bundle reference for System.framework.
-
- path = CFSTR( "/System/Library/Frameworks/System.framework" );
- url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true );
- require_action_quiet( url, exit, err = memFullErr );
-
- bundle = CFBundleCreate( NULL, url );
- CFRelease( url );
- require_action_quiet( bundle, exit, err = memFullErr );
-
- // Get a ptr to the system's "printf" function from System.framework.
-
- functionName = CFSTR( "printf" );
- functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName );
- require_action_quiet( functionPtr, exit, err = memFullErr );
-
- // Success! Note: The bundle cannot be released because it would invalidate the function ptr.
-
- gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr;
- bundle = NULL;
- err = noErr;
-
-exit:
- if( bundle )
- {
- CFRelease( bundle );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// DebugMacOSXLogPrint
-//===========================================================================================================================
-
-static void DebugMacOSXLogPrint( char *inData, size_t inSize )
-{
- if( gDebugMacOSXLogFunction )
- {
- gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData );
- }
-}
-#endif
-
-#if( TARGET_OS_WIN32 )
-//===========================================================================================================================
-// DebugWindowsDebuggerPrint
-//===========================================================================================================================
-
-void DebugWindowsDebuggerPrint( char *inData, size_t inSize )
-{
- TCHAR buffer[ 512 ];
- const char * src;
- const char * end;
- TCHAR * dst;
- char c;
-
- // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
- // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
-
- src = inData;
- if( inSize >= sizeof_array( buffer ) )
- {
- inSize = sizeof_array( buffer ) - 1;
- }
- end = src + inSize;
- dst = buffer;
- while( src < end )
- {
- c = *src++;
- if( c == '\r' )
- {
- c = '\n';
- }
- *dst++ = (TCHAR) c;
- }
- *dst = 0;
-
- // Print out the string to the debugger.
-
- OutputDebugString( buffer );
-}
-#endif
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-//===========================================================================================================================
-// DebugWindowsEventLogInit
-//===========================================================================================================================
-
-static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule )
-{
- OSStatus err;
- HKEY key;
- TCHAR name[ 128 ];
- const char * src;
- TCHAR path[ MAX_PATH ];
- size_t size;
- DWORD typesSupported;
- DWORD n;
-
- key = NULL;
-
- // Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds.
-
- if( !inName || ( *inName == '\0' ) )
- {
- inName = "DefaultApp";
- }
- DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL );
-
- // Build the path string using the fixed registry path and app name.
-
- src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
- DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size );
- DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL );
-
- // Add/Open the source name as a sub-key under the Application key in the EventLog registry key.
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL );
- require_noerr_quiet( err, exit );
-
- // Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator.
-
- n = GetModuleFileName( inModule, path, sizeof_array( path ) );
- err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr );
- require_noerr_quiet( err, exit );
- n += 1;
- n *= sizeof( TCHAR );
-
- err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
- require_noerr_quiet( err, exit );
-
- // Set the supported event types in the TypesSupported subkey.
-
- typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE |
- EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
- err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
- require_noerr_quiet( err, exit );
-
- // Set up the event source.
-
- gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name );
- err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr );
- require_noerr_quiet( err, exit );
-
-exit:
- if( key )
- {
- RegCloseKey( key );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// DebugWindowsEventLogPrint
-//===========================================================================================================================
-
-static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize )
-{
- WORD type;
- TCHAR buffer[ 512 ];
- const char * src;
- const char * end;
- TCHAR * dst;
- char c;
- const TCHAR * array[ 1 ];
-
- // Map the debug level to a Windows EventLog type.
-
- if( inLevel <= kDebugLevelNotice )
- {
- type = EVENTLOG_INFORMATION_TYPE;
- }
- else if( inLevel <= kDebugLevelWarning )
- {
- type = EVENTLOG_WARNING_TYPE;
- }
- else
- {
- type = EVENTLOG_ERROR_TYPE;
- }
-
- // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
- // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
-
- src = inData;
- if( inSize >= sizeof_array( buffer ) )
- {
- inSize = sizeof_array( buffer ) - 1;
- }
- end = src + inSize;
- dst = buffer;
- while( src < end )
- {
- c = *src++;
- if( c == '\r' )
- {
- c = '\n';
- }
- *dst++ = (TCHAR) c;
- }
- *dst = 0;
-
- // Add the the string to the event log.
-
- array[ 0 ] = buffer;
- if( gDebugWindowsEventLogEventSource )
- {
- ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL );
- }
-}
-#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
-
-#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
-//===========================================================================================================================
-// DebugAssertOutputHandler
-//===========================================================================================================================
-
-static pascal void
- DebugAssertOutputHandler(
- OSType inComponentSignature,
- UInt32 inOptions,
- const char * inAssertString,
- const char * inExceptionString,
- const char * inErrorString,
- const char * inFileName,
- long inLineNumber,
- void * inValue,
- ConstStr255Param inOutputMsg )
-{
- DEBUG_UNUSED( inComponentSignature );
- DEBUG_UNUSED( inOptions );
- DEBUG_UNUSED( inExceptionString );
- DEBUG_UNUSED( inValue );
- DEBUG_UNUSED( inOutputMsg );
-
- DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" );
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-//===========================================================================================================================
-// DebugSNPrintF
-//
-// Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes:
-//
-// Changed names to avoid name collisions with the mDNS versions.
-// Changed types to standard C types since mDNSEmbeddedAPI.h may not be available.
-// Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h.
-// Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
-// Added %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
-// Added %.8a - FIbre Channel address. Arg=ptr to address.
-// Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
-// Added %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
-// Added %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
-// Added %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
-// Added %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
-// Added %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc.
-// Added %S - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr.
-// Added %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
-// Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
-// Added %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...)
- {
- size_t length;
-
- va_list ptr;
- va_start(ptr,fmt);
- length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr);
- va_end(ptr);
-
- return(length);
- }
-
-//===========================================================================================================================
-// DebugSNPrintFVAList - va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg)
- {
- static const struct DebugSNPrintF_format
- {
- unsigned leftJustify : 1;
- unsigned forceSign : 1;
- unsigned zeroPad : 1;
- unsigned havePrecision : 1;
- unsigned hSize : 1;
- char lSize;
- char altForm;
- char sign; // +, - or space
- unsigned int fieldWidth;
- unsigned int precision;
- } DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- size_t nwritten = 0;
- int c;
- if (buflen == 0) return(0);
- buflen--; // Pre-reserve one space in the buffer for the terminating nul
- if (buflen == 0) goto exit;
-
- for (c = *fmt; c != 0; c = *++fmt)
- {
- if (c != '%')
- {
- *sbuffer++ = (char)c;
- if (++nwritten >= buflen) goto exit;
- }
- else
- {
- size_t i=0, j;
- // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
- // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
- // The size needs to be enough for a 256-byte domain name plus some error text.
- #define mDNS_VACB_Size 300
- char mDNS_VACB[mDNS_VACB_Size];
- #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
- #define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s))
- char *s = mDNS_VACB_Lim;
- const char *digits = "0123456789ABCDEF";
- struct DebugSNPrintF_format F = DebugSNPrintF_format_default;
-
- for(;;) // decode flags
- {
- c = *++fmt;
- if (c == '-') F.leftJustify = 1;
- else if (c == '+') F.forceSign = 1;
- else if (c == ' ') F.sign = ' ';
- else if (c == '#') F.altForm++;
- else if (c == '0') F.zeroPad = 1;
- else break;
- }
-
- if (c == '*') // decode field width
- {
- int f = va_arg(arg, int);
- if (f < 0) { f = -f; F.leftJustify = 1; }
- F.fieldWidth = (unsigned int)f;
- c = *++fmt;
- }
- else
- {
- for (; c >= '0' && c <= '9'; c = *++fmt)
- F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
- }
-
- if (c == '.') // decode precision
- {
- if ((c = *++fmt) == '*')
- { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
- else for (; c >= '0' && c <= '9'; c = *++fmt)
- F.precision = (10 * F.precision) + (c - '0');
- F.havePrecision = 1;
- }
-
- if (F.leftJustify) F.zeroPad = 0;
-
- conv:
- switch (c) // perform appropriate conversion
- {
- #if TYPE_LONGLONG_NATIVE
- unsigned_long_long_compat n;
- unsigned_long_long_compat base;
- #else
- unsigned long n;
- unsigned long base;
- #endif
- case 'h' : F.hSize = 1; c = *++fmt; goto conv;
- case 'l' : // fall through
- case 'L' : F.lSize++; c = *++fmt; goto conv;
- case 'd' :
- case 'i' : base = 10;
- goto canBeSigned;
- case 'u' : base = 10;
- goto notSigned;
- case 'o' : base = 8;
- goto notSigned;
- case 'b' : base = 2;
- goto notSigned;
- case 'p' : n = va_arg(arg, uintptr_t);
- F.havePrecision = 1;
- F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16;
- F.sign = 0;
- base = 16;
- c = 'x';
- goto number;
- case 'x' : digits = "0123456789abcdef";
- case 'X' : base = 16;
- goto notSigned;
- canBeSigned:
- #if TYPE_LONGLONG_NATIVE
- if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long);
- else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat);
- else n = (unsigned_long_long_compat)va_arg(arg, int);
- #else
- if (F.lSize == 1) n = (unsigned long)va_arg(arg, long);
- else if (F.lSize == 2) goto exit;
- else n = (unsigned long)va_arg(arg, int);
- #endif
- if (F.hSize) n = (short) n;
- #if TYPE_LONGLONG_NATIVE
- if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; }
- #else
- if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
- #endif
- else if (F.forceSign) F.sign = '+';
- goto number;
-
- notSigned: if (F.lSize == 1) n = va_arg(arg, unsigned long);
- else if (F.lSize == 2)
- {
- #if TYPE_LONGLONG_NATIVE
- n = va_arg(arg, unsigned_long_long_compat);
- #else
- goto exit;
- #endif
- }
- else n = va_arg(arg, unsigned int);
- if (F.hSize) n = (unsigned short) n;
- F.sign = 0;
- goto number;
-
- number: if (!F.havePrecision)
- {
- if (F.zeroPad)
- {
- F.precision = F.fieldWidth;
- if (F.altForm) F.precision -= 2;
- if (F.sign) --F.precision;
- }
- if (F.precision < 1) F.precision = 1;
- }
- if (F.precision > mDNS_VACB_Size - 1)
- F.precision = mDNS_VACB_Size - 1;
- for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]);
- for (; i < F.precision; i++) *--s = '0';
- if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
- if (F.sign) { *--s = F.sign; i++; }
- break;
-
- case 'a' : {
- unsigned char *a = va_arg(arg, unsigned char *);
- char pre[4] = "";
- char post[32] = "";
- if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
- else
- {
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- if (F.altForm == 1)
- {
- #if(defined(MDNS_DEBUGMSGS))
- mDNSAddr *ip = (mDNSAddr*)a;
- switch (ip->type)
- {
- case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break;
- case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
- default: F.precision = 0; break;
- }
- #else
- F.precision = 0; // mDNSEmbeddedAPI.h not included so no mDNSAddr support
- #endif
- }
- else if (F.altForm == 2)
- {
- #ifdef AF_INET
- const struct sockaddr *sa;
- unsigned char *port;
- sa = (const struct sockaddr*)a;
- switch (sa->sa_family)
- {
- case AF_INET: F.precision = 4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr;
- port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port;
- DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break;
- #ifdef AF_INET6
- case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr;
- pre[0] = '['; pre[1] = '\0';
- port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port;
- DebugSNPrintF(post, sizeof(post), "%%%d]:%d",
- (int)((const struct sockaddr_in6 *)sa)->sin6_scope_id,
- (port[0] << 8) | port[1]); break;
- #endif
- default: F.precision = 0; break;
- }
- #else
- F.precision = 0; // socket interfaces not included so no sockaddr support
- #endif
- }
- switch (F.precision)
- {
- case 4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s",
- a[0], a[1], a[2], a[3], post); break;
- case 6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
- a[0], a[1], a[2], a[3], a[4], a[5]); break;
- case 8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
- a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
- case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB),
- "%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s",
- pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8],
- a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break;
- default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
- "(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break;
- }
- }
- }
- break;
-
- case 'U' : {
- unsigned char *a = va_arg(arg, unsigned char *);
- if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
- else
- {
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- *((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]),
- a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break;
- }
- }
- break;
-
- case 'c' : *--s = (char)va_arg(arg, int); i = 1; break;
-
- case 'C' : if (F.lSize) n = va_arg(arg, unsigned long);
- else n = va_arg(arg, unsigned int);
- if (F.hSize) n = (unsigned short) n;
- c = (int)( n & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
- c = (int)((n >> 8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
- c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
- c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
- i = 4;
- break;
-
- case 's' : s = va_arg(arg, char *);
- if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
- else switch (F.altForm)
- {
- case 0: i=0;
- if (F.havePrecision) // C string
- {
- while((i < F.precision) && s[i]) i++;
- // Make sure we don't truncate in the middle of a UTF-8 character.
- // If the last character is part of a multi-byte UTF-8 character, back up to the start of it.
- j=0;
- while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break; }
- // If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back.
- if((j > 1) && (j <= 6))
- {
- int test = (0xFF << (8-j)) & 0xFF;
- int mask = test | (1 << ((8-j)-1));
- if((c & mask) == test) i += j;
- }
- }
- else
- while(s[i]) i++;
- break;
- case 1: i = (unsigned char) *s++; break; // Pascal string
- case 2: { // DNS label-sequence name
- unsigned char *a = (unsigned char *)s;
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- if (*a == 0) *s++ = '.'; // Special case for root DNS name
- while (*a)
- {
- if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
- if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
- s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a);
- a += 1 + *a;
- }
- i = (size_t)(s - mDNS_VACB);
- s = mDNS_VACB; // Reset s back to the start of the buffer
- break;
- }
- }
- if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character
- { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
- break;
-
- case 'S': { // UTF-16 string
- unsigned char *a = va_arg(arg, unsigned char *);
- uint16_t *u = (uint16_t*)a;
- if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
- if ((!F.havePrecision || F.precision))
- {
- if ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; } // Big Endian
- else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; } // Little Endian
- }
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- switch (F.altForm)
- {
- case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Host Endian
- { c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; }
- break;
- case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Big Endian
- { c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
- break;
- case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Little Endian
- { c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
- break;
- }
- }
- s = mDNS_VACB; // Reset s back to the start of the buffer
- break;
-
- #if TARGET_OS_MAC
- case '@': { // Cocoa/CoreFoundation object
- CFTypeRef cfObj;
- CFStringRef cfStr;
- cfObj = (CFTypeRef) va_arg(arg, void *);
- cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj);
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- if (cfStr)
- {
- CFRange range;
- CFIndex m;
- range = CFRangeMake(0, CFStringGetLength(cfStr));
- m = 0;
- CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m);
- CFRelease(cfStr);
- i = (size_t) m;
- }
- else
- {
- i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" );
- }
- }
- if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character
- { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
- break;
- #endif
-
- case 'm' : { // Error Message
- long err;
- if (F.lSize) err = va_arg(arg, long);
- else err = va_arg(arg, int);
- if (F.hSize) err = (short)err;
- DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB));
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- for(i=0;s[i];i++) {}
- }
- break;
-
- case 'H' : { // Hex Dump
- void *a = va_arg(arg, void *);
- size_t size = (size_t)va_arg(arg, int);
- size_t max = (size_t)va_arg(arg, int);
- DebugFlags flags =
- kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
- kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator |
- kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount;
- if (F.altForm == 0) flags |= kDebugFlagsNoASCII;
- size = (max < size) ? max : size;
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB));
- }
- break;
-
- case 'v' : { // Version
- uint32_t version;
- version = va_arg(arg, unsigned int);
- DebugNumVersionToString(version, mDNS_VACB);
- s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
- for(i=0;s[i];i++) {}
- }
- break;
-
- case 'n' : s = va_arg(arg, char *);
- if (F.hSize) * (short *) s = (short)nwritten;
- else if (F.lSize) * (long *) s = (long)nwritten;
- else * (int *) s = (int)nwritten;
- continue;
-
- default: s = mDNS_VACB;
- i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
-
- case '%' : *sbuffer++ = (char)c;
- if (++nwritten >= buflen) goto exit;
- break;
- }
-
- if (i < F.fieldWidth && !F.leftJustify) // Pad on the left
- do {
- *sbuffer++ = ' ';
- if (++nwritten >= buflen) goto exit;
- } while (i < --F.fieldWidth);
-
- if (i > buflen - nwritten) // Make sure we don't truncate in the middle of a UTF-8 character
- { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
- for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result
- nwritten += i;
- if (nwritten >= buflen) goto exit;
-
- for (; i < F.fieldWidth; i++) // Pad on the right
- {
- *sbuffer++ = ' ';
- if (++nwritten >= buflen) goto exit;
- }
- }
- }
- exit:
- *sbuffer++ = 0;
- return(nwritten);
- }
-
-//===========================================================================================================================
-// DebugGetErrorString
-//===========================================================================================================================
-
-DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize )
-{
- const char * s;
- char * dst;
- char * end;
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
- char buffer[ 256 ];
-#endif
-
- switch( inErrorCode )
- {
- #define CaseErrorString( X, STR ) case X: s = STR; break
- #define CaseErrorStringify( X ) case X: s = # X; break
- #define CaseErrorStringifyHardCode( VALUE, X ) case VALUE: s = # X; break
-
- // General Errors
-
- CaseErrorString( 0, "no error" );
- CaseErrorString( 1, "in-progress/waiting" );
- CaseErrorString( -1, "catch-all unknown error" );
-
- // ACP Errors
-
- CaseErrorStringifyHardCode( -2, kACPBadRequestErr );
- CaseErrorStringifyHardCode( -3, kACPNoMemoryErr );
- CaseErrorStringifyHardCode( -4, kACPBadParamErr );
- CaseErrorStringifyHardCode( -5, kACPNotFoundErr );
- CaseErrorStringifyHardCode( -6, kACPBadChecksumErr );
- CaseErrorStringifyHardCode( -7, kACPCommandNotHandledErr );
- CaseErrorStringifyHardCode( -8, kACPNetworkErr );
- CaseErrorStringifyHardCode( -9, kACPDuplicateCommandHandlerErr );
- CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr );
- CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr );
- CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr );
- CaseErrorStringifyHardCode( -13, kACPNoResourcesErr );
- CaseErrorStringifyHardCode( -14, kACPBadOptionErr );
- CaseErrorStringifyHardCode( -15, kACPBadSizeErr );
- CaseErrorStringifyHardCode( -16, kACPBadPasswordErr );
- CaseErrorStringifyHardCode( -17, kACPNotInitializedErr );
- CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr );
- CaseErrorStringifyHardCode( -19, kACPBadVersionErr );
- CaseErrorStringifyHardCode( -20, kACPBadSignatureErr );
- CaseErrorStringifyHardCode( -21, kACPBadIndexErr );
- CaseErrorStringifyHardCode( -22, kACPUnsupportedErr );
- CaseErrorStringifyHardCode( -23, kACPInUseErr );
- CaseErrorStringifyHardCode( -24, kACPParamCountErr );
- CaseErrorStringifyHardCode( -25, kACPIDErr );
- CaseErrorStringifyHardCode( -26, kACPFormatErr );
- CaseErrorStringifyHardCode( -27, kACPUnknownUserErr );
- CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr );
- CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr );
-
- // Common Services Errors
-
- CaseErrorStringify( kUnknownErr );
- CaseErrorStringify( kOptionErr );
- CaseErrorStringify( kSelectorErr );
- CaseErrorStringify( kExecutionStateErr );
- CaseErrorStringify( kPathErr );
- CaseErrorStringify( kParamErr );
- CaseErrorStringify( kParamCountErr );
- CaseErrorStringify( kCommandErr );
- CaseErrorStringify( kIDErr );
- CaseErrorStringify( kStateErr );
- CaseErrorStringify( kRangeErr );
- CaseErrorStringify( kRequestErr );
- CaseErrorStringify( kResponseErr );
- CaseErrorStringify( kChecksumErr );
- CaseErrorStringify( kNotHandledErr );
- CaseErrorStringify( kVersionErr );
- CaseErrorStringify( kSignatureErr );
- CaseErrorStringify( kFormatErr );
- CaseErrorStringify( kNotInitializedErr );
- CaseErrorStringify( kAlreadyInitializedErr );
- CaseErrorStringify( kNotInUseErr );
- CaseErrorStringify( kInUseErr );
- CaseErrorStringify( kTimeoutErr );
- CaseErrorStringify( kCanceledErr );
- CaseErrorStringify( kAlreadyCanceledErr );
- CaseErrorStringify( kCannotCancelErr );
- CaseErrorStringify( kDeletedErr );
- CaseErrorStringify( kNotFoundErr );
- CaseErrorStringify( kNoMemoryErr );
- CaseErrorStringify( kNoResourcesErr );
- CaseErrorStringify( kDuplicateErr );
- CaseErrorStringify( kImmutableErr );
- CaseErrorStringify( kUnsupportedDataErr );
- CaseErrorStringify( kIntegrityErr );
- CaseErrorStringify( kIncompatibleErr );
- CaseErrorStringify( kUnsupportedErr );
- CaseErrorStringify( kUnexpectedErr );
- CaseErrorStringify( kValueErr );
- CaseErrorStringify( kNotReadableErr );
- CaseErrorStringify( kNotWritableErr );
- CaseErrorStringify( kBadReferenceErr );
- CaseErrorStringify( kFlagErr );
- CaseErrorStringify( kMalformedErr );
- CaseErrorStringify( kSizeErr );
- CaseErrorStringify( kNameErr );
- CaseErrorStringify( kNotReadyErr );
- CaseErrorStringify( kReadErr );
- CaseErrorStringify( kWriteErr );
- CaseErrorStringify( kMismatchErr );
- CaseErrorStringify( kDateErr );
- CaseErrorStringify( kUnderrunErr );
- CaseErrorStringify( kOverrunErr );
- CaseErrorStringify( kEndingErr );
- CaseErrorStringify( kConnectionErr );
- CaseErrorStringify( kAuthenticationErr );
- CaseErrorStringify( kOpenErr );
- CaseErrorStringify( kTypeErr );
- CaseErrorStringify( kSkipErr );
- CaseErrorStringify( kNoAckErr );
- CaseErrorStringify( kCollisionErr );
- CaseErrorStringify( kBackoffErr );
- CaseErrorStringify( kNoAddressAckErr );
- CaseErrorStringify( kBusyErr );
- CaseErrorStringify( kNoSpaceErr );
-
- // mDNS/DNS-SD Errors
-
- CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr );
- CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr );
- CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr );
- CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr );
- CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr );
- CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr );
- CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr );
- CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr );
- CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr );
- CaseErrorStringifyHardCode( -65546, mStatus_NoCache );
- CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered );
- CaseErrorStringifyHardCode( -65548, mStatus_NameConflict );
- CaseErrorStringifyHardCode( -65549, mStatus_Invalid );
- CaseErrorStringifyHardCode( -65550, mStatus_GrowCache );
- CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr );
- CaseErrorStringifyHardCode( -65552, mStatus_Incompatible );
- CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged );
- CaseErrorStringifyHardCode( -65792, mStatus_MemFree );
-
- // RSP Errors
-
- CaseErrorStringifyHardCode( -400000, kRSPUnknownErr );
- CaseErrorStringifyHardCode( -400050, kRSPParamErr );
- CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr );
- CaseErrorStringifyHardCode( -405246, kRSPRangeErr );
- CaseErrorStringifyHardCode( -409057, kRSPSizeErr );
- CaseErrorStringifyHardCode( -400200, kRSPHardwareErr );
- CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr );
- CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr );
- CaseErrorStringifyHardCode( -402419, kRSPIDErr );
- CaseErrorStringifyHardCode( -403165, kRSPFlagErr );
- CaseErrorString( -200000, "kRSPControllerStatusBase - 0x50" );
- CaseErrorString( -200080, "kRSPCommandSucceededErr - 0x50" );
- CaseErrorString( -200001, "kRSPCommandFailedErr - 0x01" );
- CaseErrorString( -200051, "kRSPChecksumErr - 0x33" );
- CaseErrorString( -200132, "kRSPCommandTimeoutErr - 0x84" );
- CaseErrorString( -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" );
- CaseErrorString( -200128, "kRSPCanceledErr - 0x02 Async" );
-
- // XML Errors
-
- CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr );
- CaseErrorStringifyHardCode( -100050, kXMLParamErr );
- CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr );
- CaseErrorStringifyHardCode( -100206, kXMLFormatErr );
- CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr );
- CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr );
- CaseErrorStringifyHardCode( -101726, kXMLKeyErr );
- CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr );
- CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr );
- CaseErrorStringifyHardCode( -103026, kXMLParseErr );
- CaseErrorStringifyHardCode( -103159, kXMLBadDataErr );
- CaseErrorStringifyHardCode( -103170, kXMLBadNameErr );
- CaseErrorStringifyHardCode( -105246, kXMLRangeErr );
- CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr );
- CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr );
- CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr );
- CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr );
- CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr );
- CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr );
- CaseErrorStringifyHardCode( -102015, kXMLDateErr );
-
- #if( __MACH__ )
-
- // Mach Errors
-
- CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE );
- CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE );
- CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL );
- CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL );
- CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS );
- CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA );
- CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST );
- CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT );
- CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED );
- CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL );
- CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY );
- CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT );
- CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY );
- CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY );
- CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER );
- CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE );
- CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE );
- CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER );
- CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER );
- CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE );
- CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS );
- CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME );
- CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT );
- CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE );
- CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED );
- CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED );
- CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY );
- CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA );
- CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED );
- CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET );
- CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR );
- CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR );
- CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE );
- CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL );
- CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER );
- CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED );
-
- // Mach OSReturn Errors
-
- CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError );
- CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal );
- CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances );
- CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit );
- CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData );
- CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts );
- CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet );
- CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet );
- CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper );
- CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper );
- CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass );
-
- // IOKit Errors
-
- CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError );
- CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory );
- CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources );
- CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError );
- CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice );
- CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged );
- CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument );
- CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead );
- CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite );
- CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess );
- CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID );
- CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported );
- CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError );
- CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError );
- CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError );
- CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock );
- CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen );
- CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable );
- CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable );
- CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned );
- CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia );
- CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen );
- CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError );
- CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError );
- CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy );
- CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout );
- CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline );
- CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady );
- CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached );
- CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels );
- CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace );
- CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists );
- CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire );
- CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt );
- CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames );
- CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge );
- CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted );
- CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower );
- CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia );
- CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia );
- CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode );
- CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun );
- CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun );
- CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError );
- CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion );
- CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted );
- CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth );
- CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding );
- CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld );
- CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew );
- CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound );
- CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid );
-
- // IOKit FireWire Errors
-
- CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase );
- CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset );
- CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry );
- CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending );
- CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken );
- CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid );
- CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered );
- CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers );
- CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive );
- CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker );
- CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels );
- CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable );
- CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus );
- CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs );
- CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage );
- CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower );
- CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels );
- CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram );
- CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening );
- CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept );
- CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose );
- CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged );
- CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged );
-
- // IOKit USB Errors
-
- CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr );
- CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr );
- CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr );
- CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr );
- CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr );
- CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound );
- CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound );
- CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout );
- CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned );
- CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled );
- CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound );
- CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated );
- CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated );
- CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError );
- CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr );
- CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err );
- CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err );
- CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr );
- CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr );
- CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err );
- CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err );
- CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr );
- CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr );
- CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr );
- CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr );
- CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr );
-
- #endif // __MACH__
-
- // Other Errors
-
- default:
- s = NULL;
- #if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
- if( inBuffer && ( inBufferSize > 0 ) )
- {
- DWORD n;
-
- n = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) inErrorCode,
- MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), buffer, sizeof( buffer ), NULL );
- if( n > 0 )
- {
- // Remove any trailing CR's or LF's since some messages have them.
-
- while( ( n > 0 ) && isspace( ( (unsigned char *) buffer )[ n - 1 ] ) )
- {
- buffer[ --n ] = '\0';
- }
- s = buffer;
- }
- }
- #endif
-
- if( !s )
- {
- #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
- s = strerror( inErrorCode );
- #endif
- if( !s )
- {
- s = "<unknown error code>";
- }
- }
- break;
- }
-
- // Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string.
-
- if( inBuffer && ( inBufferSize > 0 ) )
- {
- dst = inBuffer;
- end = dst + ( inBufferSize - 1 );
- while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) )
- {
- *dst++ = *s++;
- }
- *dst = '\0';
- s = inBuffer;
- }
- return( s );
-}
-
-//===========================================================================================================================
-// DebugHexDump
-//===========================================================================================================================
-
-DEBUG_EXPORT size_t
- DebugHexDump(
- DebugLevel inLevel,
- int inIndent,
- const char * inLabel,
- size_t inLabelSize,
- int inLabelMinWidth,
- const char * inType,
- size_t inTypeSize,
- const void * inDataStart,
- const void * inData,
- size_t inDataSize,
- DebugFlags inFlags,
- char * outBuffer,
- size_t inBufferSize )
-{
- static const char kHexChars[] = "0123456789ABCDEF";
- const uint8_t * start;
- const uint8_t * src;
- char * dst;
- char * end;
- size_t n;
- int offset;
- int width;
- const char * newline;
- char separator[ 8 ];
- char * s;
-
- DEBUG_UNUSED( inType );
- DEBUG_UNUSED( inTypeSize );
-
- // Set up the function-wide variables.
-
- if( inLabelSize == kSizeCString )
- {
- inLabelSize = strlen( inLabel );
- }
- start = (const uint8_t *) inData;
- src = start;
- dst = outBuffer;
- end = dst + inBufferSize;
- offset = (int)( (intptr_t) inData - (intptr_t) inDataStart );
- width = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth;
- newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n";
-
- // Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines.
-
- s = separator;
- if( inFlags & kDebugFlagsNoNewLine )
- {
- if( inFlags & kDebugFlags8BitSeparator )
- {
- *s++ = ' ';
- }
- if( inFlags & kDebugFlags16BitSeparator )
- {
- *s++ = ' ';
- }
- if( !( inFlags & kDebugFlagsNo32BitSeparator ) )
- {
- *s++ = ' ';
- }
- check( ( (size_t)( s - separator ) ) < sizeof( separator ) );
- }
- *s = '\0';
-
- for( ;; )
- {
- char prefixString[ 32 ];
- char hexString[ 64 ];
- char asciiString[ 32 ];
- char byteCountString[ 32 ];
- int c;
- size_t chunkSize;
- size_t i;
-
- // If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit.
-
- if( inDataSize == 0 )
- {
- if( inLabel && ( inLabelSize > 0 ) )
- {
- width = 0;
- if( !( inFlags & kDebugFlagsNoAddress ) )
- {
- width += 8; // "00000000"
- if( !( inFlags & kDebugFlagsNoOffset ) )
- {
- width += 1; // "+"
- }
- }
- if( inFlags & kDebugFlags32BitOffset )
- {
- width += 8; // "00000000"
- }
- else if( !( inFlags & kDebugFlagsNoOffset ) )
- {
- width += 4; // "0000"
- }
-
- if( outBuffer )
- {
- dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s",
- width, "",
- ( width > 0 ) ? ": " : "",
- width, (int) inLabelSize, inLabel,
- newline );
- }
- else
- {
- dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s",
- width, "",
- ( width > 0 ) ? ": " : "",
- width, (int) inLabelSize, inLabel,
- newline );
- }
- }
- break;
- }
-
- // Build the prefix string. It will be in one of the following formats:
- //
- // 1) "00000000+0000[0000]" (address and offset)
- // 2) "00000000" (address only)
- // 3) "0000[0000]" (offset only)
- // 4) "" (no address or offset)
- //
- // Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate.
-
- s = prefixString;
- if( !( inFlags & kDebugFlagsNoAddress ) )
- {
- *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ];
- *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ];
- *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ];
- *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ];
- *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ];
- *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 8 ) & 0xF ];
- *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 4 ) & 0xF ];
- *s++ = kHexChars[ ( (uintptr_t) src ) & 0xF ];
-
- if( !( inFlags & kDebugFlagsNoOffset ) )
- {
- *s++ = '+';
- }
- }
- if( !( inFlags & kDebugFlagsNoOffset ) )
- {
- if( inFlags & kDebugFlags32BitOffset )
- {
- *s++ = kHexChars[ ( offset >> 28 ) & 0xF ];
- *s++ = kHexChars[ ( offset >> 24 ) & 0xF ];
- *s++ = kHexChars[ ( offset >> 20 ) & 0xF ];
- *s++ = kHexChars[ ( offset >> 16 ) & 0xF ];
- }
- *s++ = kHexChars[ ( offset >> 12 ) & 0xF ];
- *s++ = kHexChars[ ( offset >> 8 ) & 0xF ];
- *s++ = kHexChars[ ( offset >> 4 ) & 0xF ];
- *s++ = kHexChars[ offset & 0xF ];
- }
- if( s != prefixString )
- {
- *s++ = ':';
- *s++ = ' ';
- }
- check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) );
- *s = '\0';
-
- // Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read.
- // Optionally pads the hex string with space to fill the full 16 byte range (so it lines up).
-
- s = hexString;
- chunkSize = ( inDataSize < 16 ) ? inDataSize : 16;
- n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16;
- for( i = 0; i < n; ++i )
- {
- if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) )
- {
- *s++ = ' ';
- }
- if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) )
- {
- *s++ = ' ';
- }
- if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) )
- {
- *s++ = ' ';
- }
- if( i < chunkSize )
- {
- *s++ = kHexChars[ src[ i ] >> 4 ];
- *s++ = kHexChars[ src[ i ] & 0xF ];
- }
- else
- {
- *s++ = ' ';
- *s++ = ' ';
- }
- }
- check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) );
- *s = '\0';
-
- // Build a string with the ASCII version of the data (replaces non-printable characters with '^').
- // Optionally pads the string with '`' to fill the full 16 byte range (so it lines up).
-
- s = asciiString;
- if( !( inFlags & kDebugFlagsNoASCII ) )
- {
- *s++ = ' ';
- *s++ = '|';
- for( i = 0; i < n; ++i )
- {
- if( i < chunkSize )
- {
- c = src[ i ];
- if( !DebugIsPrint( c ) )
- {
- c = '^';
- }
- }
- else
- {
- c = '`';
- }
- *s++ = (char) c;
- }
- *s++ = '|';
- check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) );
- }
- *s = '\0';
-
- // Build a string indicating how bytes are in the hex dump. Only printed on the first line.
-
- s = byteCountString;
- if( !( inFlags & kDebugFlagsNoByteCount ) )
- {
- if( src == start )
- {
- s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize );
- }
- }
- check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) );
- *s = '\0';
-
- // Build the entire line from all the pieces we've previously built.
-
- if( outBuffer )
- {
- if( src == start )
- {
- dst += DebugSNPrintF( dst, (size_t)( end - dst ),
- "%*s" // Indention
- "%s" // Separator (only if needed)
- "%s" // Prefix
- "%-*.*s" // Label
- "%s" // Separator
- "%s" // Hex
- "%s" // ASCII
- "%s" // Byte Count
- "%s", // Newline
- inIndent, "",
- ( src != start ) ? separator : "",
- prefixString,
- width, (int) inLabelSize, inLabel ? inLabel : "",
- ( width > 0 ) ? " " : "",
- hexString,
- asciiString,
- byteCountString,
- newline );
- }
- else
- {
- dst += DebugSNPrintF( dst, (size_t)( end - dst ),
- "%*s" // Indention
- "%s" // Separator (only if needed)
- "%s" // Prefix
- "%*s" // Label Spacing
- "%s" // Separator
- "%s" // Hex
- "%s" // ASCII
- "%s" // Byte Count
- "%s", // Newline
- inIndent, "",
- ( src != start ) ? separator : "",
- prefixString,
- width, "",
- ( width > 0 ) ? " " : "",
- hexString,
- asciiString,
- byteCountString,
- newline );
- }
- }
- else
- {
- if( src == start )
- {
- dst += DebugPrintF( inLevel,
- "%*s" // Indention
- "%s" // Separator (only if needed)
- "%s" // Prefix
- "%-*.*s" // Label
- "%s" // Separator
- "%s" // Hex
- "%s" // ASCII
- "%s" // Byte Count
- "%s", // Newline
- inIndent, "",
- ( src != start ) ? separator : "",
- prefixString,
- width, (int) inLabelSize, inLabel,
- ( width > 0 ) ? " " : "",
- hexString,
- asciiString,
- byteCountString,
- newline );
- }
- else
- {
- dst += DebugPrintF( inLevel,
- "%*s" // Indention
- "%s" // Separator (only if needed)
- "%s" // Prefix
- "%*s" // Label Spacing
- "%s" // Separator
- "%s" // Hex
- "%s" // ASCII
- "%s" // Byte Count
- "%s", // Newline
- inIndent, "",
- ( src != start ) ? separator : "",
- prefixString,
- width, "",
- ( width > 0 ) ? " " : "",
- hexString,
- asciiString,
- byteCountString,
- newline );
- }
- }
-
- // Move to the next chunk. Exit if there is no more data.
-
- offset += (int) chunkSize;
- src += chunkSize;
- inDataSize -= chunkSize;
- if( inDataSize == 0 )
- {
- break;
- }
- }
-
- // Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative.
-
- return( (size_t)( dst - outBuffer ) );
-}
-
-//===========================================================================================================================
-// DebugNumVersionToString
-//===========================================================================================================================
-
-static char * DebugNumVersionToString( uint32_t inVersion, char *inString )
-{
- char * s;
- uint8_t majorRev;
- uint8_t minor;
- uint8_t bugFix;
- uint8_t stage;
- uint8_t revision;
-
- check( inString );
-
- majorRev = (uint8_t)( ( inVersion >> 24 ) & 0xFF );
- minor = (uint8_t)( ( inVersion >> 20 ) & 0x0F );
- bugFix = (uint8_t)( ( inVersion >> 16 ) & 0x0F );
- stage = (uint8_t)( ( inVersion >> 8 ) & 0xFF );
- revision = (uint8_t)( inVersion & 0xFF );
-
- // Convert the major, minor, and bugfix numbers.
-
- s = inString;
- s += sprintf( s, "%u", majorRev );
- s += sprintf( s, ".%u", minor );
- if( bugFix != 0 )
- {
- s += sprintf( s, ".%u", bugFix );
- }
-
- // Convert the version stage and non-release revision number.
-
- switch( stage )
- {
- case kVersionStageDevelopment:
- s += sprintf( s, "d%u", revision );
- break;
-
- case kVersionStageAlpha:
- s += sprintf( s, "a%u", revision );
- break;
-
- case kVersionStageBeta:
- s += sprintf( s, "b%u", revision );
- break;
-
- case kVersionStageFinal:
-
- // A non-release revision of zero is a special case indicating the software is GM (at the golden master
- // stage) and therefore, the non-release revision should not be added to the string.
-
- if( revision != 0 )
- {
- s += sprintf( s, "f%u", revision );
- }
- break;
-
- default:
- dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage );
- break;
- }
- return( inString );
-}
-
-//===========================================================================================================================
-// DebugTaskLevel
-//===========================================================================================================================
-
-DEBUG_EXPORT uint32_t DebugTaskLevel( void )
-{
- uint32_t level;
-
- level = 0;
-
-#if( TARGET_OS_VXWORKS )
- if( intContext() )
- {
- level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
- }
-#endif
-
- return( level );
-}
-
-#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
-//===========================================================================================================================
-// DebugWinEnableConsole
-//===========================================================================================================================
-
-#pragma warning( disable:4311 )
-
-static void DebugWinEnableConsole( void )
-{
- static bool sConsoleEnabled = false;
- BOOL result;
- int fileHandle;
- FILE * file;
- int err;
-
- if( sConsoleEnabled )
- {
- goto exit;
- }
-
- // Create console window.
-
- result = AllocConsole();
- require_quiet( result, exit );
-
- // Redirect stdin to the console stdin.
-
- fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT );
-
- #if( defined( __MWERKS__ ) )
- file = __handle_reopen( (unsigned long) fileHandle, "r", stdin );
- require_quiet( file, exit );
- #else
- file = _fdopen( fileHandle, "r" );
- require_quiet( file, exit );
-
- *stdin = *file;
- #endif
-
- err = setvbuf( stdin, NULL, _IONBF, 0 );
- require_noerr_quiet( err, exit );
-
- // Redirect stdout to the console stdout.
-
- fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
-
- #if( defined( __MWERKS__ ) )
- file = __handle_reopen( (unsigned long) fileHandle, "w", stdout );
- require_quiet( file, exit );
- #else
- file = _fdopen( fileHandle, "w" );
- require_quiet( file, exit );
-
- *stdout = *file;
- #endif
-
- err = setvbuf( stdout, NULL, _IONBF, 0 );
- require_noerr_quiet( err, exit );
-
- // Redirect stderr to the console stdout.
-
- fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
-
- #if( defined( __MWERKS__ ) )
- file = __handle_reopen( (unsigned long) fileHandle, "w", stderr );
- require_quiet( file, exit );
- #else
- file = _fdopen( fileHandle, "w" );
- require_quiet( file, exit );
-
- *stderr = *file;
- #endif
-
- err = setvbuf( stderr, NULL, _IONBF, 0 );
- require_noerr_quiet( err, exit );
-
- sConsoleEnabled = true;
-
-exit:
- return;
-}
-
-#pragma warning( default:4311 )
-
-#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
-
-#if( TARGET_OS_WIN32 )
-//===========================================================================================================================
-// DebugWinCharToTCharString
-//===========================================================================================================================
-
-static TCHAR *
- DebugWinCharToTCharString(
- const char * inCharString,
- size_t inCharCount,
- TCHAR * outTCharString,
- size_t inTCharCountMax,
- size_t * outTCharCount )
-{
- const char * src;
- TCHAR * dst;
- TCHAR * end;
-
- if( inCharCount == kSizeCString )
- {
- inCharCount = strlen( inCharString );
- }
- src = inCharString;
- dst = outTCharString;
- if( inTCharCountMax > 0 )
- {
- inTCharCountMax -= 1;
- if( inTCharCountMax > inCharCount )
- {
- inTCharCountMax = inCharCount;
- }
-
- end = dst + inTCharCountMax;
- while( dst < end )
- {
- *dst++ = (TCHAR) *src++;
- }
- *dst = 0;
- }
- if( outTCharCount )
- {
- *outTCharCount = (size_t)( dst - outTCharString );
- }
- return( outTCharString );
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == Debugging ==
-#endif
-
-//===========================================================================================================================
-// DebugServicesTest
-//===========================================================================================================================
-
-DEBUG_EXPORT OSStatus DebugServicesTest( void )
-{
- OSStatus err;
- char s[ 512 ];
- uint8_t * p;
- uint8_t data[] =
- {
- 0x11, 0x22, 0x33, 0x44,
- 0x55, 0x66,
- 0x77, 0x88, 0x99, 0xAA,
- 0xBB, 0xCC, 0xDD,
- 0xEE,
- 0xFF,
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
- 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0,
- 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1
- };
-
- debug_initialize( kDebugOutputTypeMetaConsole );
-
- // check's
-
- check( 0 && "SHOULD SEE: check" );
- check( 1 && "SHOULD *NOT* SEE: check (valid)" );
- check_string( 0, "SHOULD SEE: check_string" );
- check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" );
- check_noerr( -123 );
- check_noerr( 10038 );
- check_noerr( 22 );
- check_noerr( 0 );
- check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" );
- check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" );
- check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 );
- check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 );
- check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 );
- check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 );
- check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 5, 10 );
- check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12, 6 );
- check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 6, 10, 10 );
- check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 );
- check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 );
- check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 );
- check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 );
-
- // require's
-
- require( 0 && "SHOULD SEE", require1 );
- { err = kResponseErr; goto exit; }
-require1:
- require( 1 && "SHOULD *NOT* SEE", require2 );
- goto require2Good;
-require2:
- { err = kResponseErr; goto exit; }
-require2Good:
- require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" );
- { err = kResponseErr; goto exit; }
-require3:
- require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" );
- goto require4Good;
-require4:
- { err = kResponseErr; goto exit; }
-require4Good:
- require_quiet( 0 && "SHOULD SEE", require5 );
- { err = kResponseErr; goto exit; }
-require5:
- require_quiet( 1 && "SHOULD *NOT* SEE", require6 );
- goto require6Good;
-require6:
- { err = kResponseErr; goto exit; }
-require6Good:
- require_noerr( -1, require7 );
- { err = kResponseErr; goto exit; }
-require7:
- require_noerr( 0, require8 );
- goto require8Good;
-require8:
- { err = kResponseErr; goto exit; }
-require8Good:
- require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string");
- { err = kResponseErr; goto exit; }
-require9:
- require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" );
- goto require10Good;
-require10:
- { err = kResponseErr; goto exit; }
-require10Good:
- require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" );
- { err = kResponseErr; goto exit; }
-require11:
- require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" );
- goto require12Good;
-require12:
- { err = kResponseErr; goto exit; }
-require12Good:
- require_noerr_quiet( -4, require13 );
- { err = kResponseErr; goto exit; }
-require13:
- require_noerr_quiet( 0, require14 );
- goto require14Good;
-require14:
- { err = kResponseErr; goto exit; }
-require14Good:
- require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) );
- { err = kResponseErr; goto exit; }
-require15:
- require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) );
- goto require16Good;
-require16:
- { err = kResponseErr; goto exit; }
-require16Good:
- require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) );
- { err = kResponseErr; goto exit; }
-require17:
- require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) );
- goto require18Good;
-require18:
- { err = kResponseErr; goto exit; }
-require18Good:
- require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) );
- { err = kResponseErr; goto exit; }
-require19:
- require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) );
- goto require20Good;
-require20:
- { err = kResponseErr; goto exit; }
-require20Good:
- require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) );
- { err = kResponseErr; goto exit; }
-require21:
- require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) );
- goto require22Good;
-require22:
- { err = kResponseErr; goto exit; }
-require22Good:
- require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" );
- { err = kResponseErr; goto exit; }
-require23:
- require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" );
- goto require24Good;
-require24:
- { err = kResponseErr; goto exit; }
-require24Good:
-
-#if( defined( __MWERKS__ ) )
- #if( defined( __cplusplus ) && __option( exceptions ) )
- #define COMPILER_HAS_EXCEPTIONS 1
- #else
- #define COMPILER_HAS_EXCEPTIONS 0
- #endif
-#else
- #if( defined( __cplusplus ) )
- #define COMPILER_HAS_EXCEPTIONS 1
- #else
- #define COMPILER_HAS_EXCEPTIONS 0
- #endif
-#endif
-
-#if( COMPILER_HAS_EXCEPTIONS )
- try
- {
- require_throw( 1 && "SHOULD *NOT* SEE" );
- require_throw( 0 && "SHOULD SEE" );
- }
- catch( ... )
- {
- goto require26Good;
- }
- { err = kResponseErr; goto exit; }
-require26Good:
-#endif
-
- // translate_errno
-
- err = translate_errno( 1 != -1, -123, -567 );
- require( ( err == 0 ) && "SHOULD *NOT* SEE", exit );
-
- err = translate_errno( -1 != -1, -123, -567 );
- require( ( err == -123 ) && "SHOULD *NOT* SEE", exit );
-
- err = translate_errno( -1 != -1, 0, -567 );
- require( ( err == -567 ) && "SHOULD *NOT* SEE", exit );
-
- // debug_string
-
- debug_string( "debug_string" );
-
- // DebugSNPrintF
-
- DebugSNPrintF( s, sizeof( s ), "%d", 1234 );
- require_action( strcmp( s, "1234" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 );
- require_action( strcmp( s, "2345" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" );
- require_action( strcmp( s, "test" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" );
- require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) );
- require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) );
- require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 );
-
- #if( TYPE_LONGLONG_NATIVE )
- DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) );
- require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) );
- require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) );
- require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 );
- #endif
-
- DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) );
- require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 ); // 'AbCd'
- require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 );
-
- #if( defined( MDNS_DEBUGMSGS ) )
- {
- mDNSAddr maddr;
-
- memset( &maddr, 0, sizeof( maddr ) );
- maddr.type = mDNSAddrType_IPv4;
- maddr.ip.v4.b[ 0 ] = 127;
- maddr.ip.v4.b[ 1 ] = 0;
- maddr.ip.v4.b[ 2 ] = 0;
- maddr.ip.v4.b[ 3 ] = 1;
- DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
- require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 );
-
- memset( &maddr, 0, sizeof( maddr ) );
- maddr.type = mDNSAddrType_IPv6;
- maddr.ip.v6.b[ 0 ] = 0xFE;
- maddr.ip.v6.b[ 1 ] = 0x80;
- maddr.ip.v6.b[ 15 ] = 0x01;
- DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
- require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 );
- }
- #endif
-
- #if( AF_INET )
- {
- struct sockaddr_in sa4;
-
- memset( &sa4, 0, sizeof( sa4 ) );
- sa4.sin_family = AF_INET;
- p = (uint8_t *) &sa4.sin_port;
- p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF );
- p[ 1 ] = (uint8_t)( 80 & 0xFF );
- p = (uint8_t *) &sa4.sin_addr.s_addr;
- p[ 0 ] = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF );
- p[ 1 ] = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF );
- p[ 2 ] = (uint8_t)( ( INADDR_LOOPBACK >> 8 ) & 0xFF );
- p[ 3 ] = (uint8_t)( INADDR_LOOPBACK & 0xFF );
- DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 );
- require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 );
- }
- #endif
-
- #if( AF_INET6 )
- {
- struct sockaddr_in6 sa6;
-
- memset( &sa6, 0, sizeof( sa6 ) );
- sa6.sin6_family = AF_INET6;
- p = (uint8_t *) &sa6.sin6_port;
- p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF );
- p[ 1 ] = (uint8_t)( 80 & 0xFF );
- sa6.sin6_addr.s6_addr[ 0 ] = 0xFE;
- sa6.sin6_addr.s6_addr[ 1 ] = 0x80;
- sa6.sin6_addr.s6_addr[ 15 ] = 0x01;
- sa6.sin6_scope_id = 2;
- DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 );
- require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 );
- }
- #endif
-
- // Unicode
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" );
- require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" );
- require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" );
- require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" );
- require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" );
- require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" );
- require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" );
- require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" );
- require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" );
- require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" );
- require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" );
- require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" );
- require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
-
- DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" );
- require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
-
- #if( TARGET_RT_BIG_ENDIAN )
- DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );
- require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
- #else
- DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );
- require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
- #endif
-
- DebugSNPrintF( s, sizeof( s ), "%S",
- "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM
- require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%S",
- "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM
- require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian
- require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian
- require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%.*S",
- 4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian BOM
- require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%.*S",
- 4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian BOM
- require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-
- #if( TARGET_RT_BIG_ENDIAN )
- DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );
- require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
- #else
- DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );
- require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
- #endif
-
- DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian
- require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian
- require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
-
- // Misc
-
- DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" );
- require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%m", 0 );
- require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 );
- require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
-
- DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 );
- DebugPrintF( kDebugLevelMax, "%s\n\n", s );
-
- DebugSNPrintF( s, sizeof( s ), "\"%H\"",
- "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
- "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8",
- 32, 32 );
- DebugPrintF( kDebugLevelMax, "%s\n\n", s );
-
- DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 );
- DebugPrintF( kDebugLevelMax, "%s\n\n", s );
-
- // Hex Dumps
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNone, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNoAddress, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNoOffset, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNoAddress, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNoOffset, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNoByteCount, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4, // 'AbCd'
- kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
- kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount,
- s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
- kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine |
- kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator |
- kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- s[ 0 ] = '\0';
- DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) );
- DebugPrintF( kDebugLevelMax, "%s\n", s );
-
- // dlog's
-
- dlog( kDebugLevelNotice, "dlog\n" );
- dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 );
- dlog( kDebugLevelNotice, "dlog string: \"%s\"\n", "test string" );
- dlogmem( kDebugLevelNotice, data, sizeof( data ) );
-
- // Done
-
- DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" );
- err = kNoErr;
-
-exit:
- if( err )
- {
- DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" );
- }
- return( err );
-}
-
-#endif // DEBUG
+++ /dev/null
-/*
- * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: DebugServices.h,v $
-Revision 1.4 2004/04/15 08:59:08 bradley
-Removed deprecated debug and log levels and replaced them with modern equivalents.
-
-Revision 1.3 2004/04/08 09:29:55 bradley
-Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
-hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
-Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
-
-Revision 1.2 2004/03/07 05:59:34 bradley
-Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
-
-Revision 1.1 2004/01/30 02:27:30 bradley
-Debugging support for various platforms.
-
-*/
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @header DebugServices
-
- Debugging Library
-*/
-
-#ifndef __DEBUG_SERVICES__
-#define __DEBUG_SERVICES__
-
-#include <stdarg.h>
-
-#include "CommonServices.h"
-
-#if( TARGET_OS_VXWORKS )
- #include "logLib.h"
-#endif
-
-#if 0
-#pragma mark == Settings ==
-#endif
-
-//===========================================================================================================================
-// Settings
-//===========================================================================================================================
-
-// General
-
-#if( !defined( DEBUG ) )
- #define DEBUG 0
-#endif
-
-#if( defined( NDEBUG ) && DEBUG )
- #error NDEBUG defined and DEBUG is also enabled...they need to be in-sync
-#endif
-
-// AssertMacros.h/Debugging.h overrides.
-
-#if( !defined( DEBUG_OVERRIDE_APPLE_MACROS ) )
- #define DEBUG_OVERRIDE_APPLE_MACROS 1
-#endif
-
-// Routine name. Uses ISO __func__ where possible. Otherwise, uses the best thing that is available (if anything).
-
-#if( defined( __MWERKS__ ) || ( __GNUC__ > 2 ) || ( ( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 9 ) ) )
- #define __ROUTINE__ __func__
-#elif( defined( __GNUC__ ) )
- #define __ROUTINE__ __PRETTY_FUNCTION__
-#elif( defined( _MSC_VER ) && !defined( _WIN32_WCE ) )
- #define __ROUTINE__ __FUNCTION__
-#else
- #define __ROUTINE__ ""
-#endif
-
-// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing.
-
-#if( defined( __GNUC__ ) )
- #if( ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 3) ) )
- #define DEBUG_C99_VA_ARGS 1
- #define DEBUG_GNU_VA_ARGS 0
- #else
- #define DEBUG_C99_VA_ARGS 0
- #define DEBUG_GNU_VA_ARGS 1
- #endif
-#elif( defined( __MWERKS__ ) )
- #define DEBUG_C99_VA_ARGS 1
- #define DEBUG_GNU_VA_ARGS 0
-#else
- #define DEBUG_C99_VA_ARGS 0
- #define DEBUG_GNU_VA_ARGS 0
-#endif
-
-#if 0
-#pragma mark == Output ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_FPRINTF_ENABLED
-
- @abstract Enables ANSI C fprintf output.
-*/
-
-#if( !defined( DEBUG_FPRINTF_ENABLED ) )
- #if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
- #define DEBUG_FPRINTF_ENABLED 1
- #else
- #define DEBUG_FPRINTF_ENABLED 0
- #endif
-#else
- #if( TARGET_API_MAC_OSX_KERNEL || TARGET_OS_WINDOWS_CE )
- #error fprintf enabled, but not supported on Mac OS X kernel or Windows CE
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_MAC_OS_X_IOLOG_ENABLED
-
- @abstract Enables IOLog (Mac OS X Kernel) output.
-*/
-
-#if( !defined( DEBUG_MAC_OS_X_IOLOG_ENABLED ) )
- #define DEBUG_MAC_OS_X_IOLOG_ENABLED TARGET_API_MAC_OSX_KERNEL
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_KPRINTF_ENABLED
-
- @abstract Enables kprintf (Mac OS X Kernel) output.
-*/
-
-#if( !defined( DEBUG_KPRINTF_ENABLED ) )
- #define DEBUG_KPRINTF_ENABLED TARGET_API_MAC_OSX_KERNEL
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_IDEBUG_ENABLED
-
- @abstract Enables iDebug (Mac OS X user and Kernel) output.
-
- @discussion
-
- For Mac OS X kernel development, iDebug is enabled by default because we can dynamically check for the presence
- of iDebug via some exported IOKit symbols. Mac OS X app usage doesn't allow dynamic detection because it relies
- on statically linking to the iDebugServices.cp file so for Mac OS X app usage, you have to manually enable iDebug.
-*/
-
-#if( !defined( DEBUG_IDEBUG_ENABLED ) )
- #define DEBUG_IDEBUG_ENABLED TARGET_API_MAC_OSX_KERNEL
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_CORE_SERVICE_ASSERTS_ENABLED
-
- @abstract Controls whether Core Services assert handling is enabled. Enabling requires CoreServices framework.
-*/
-
-#if( !defined( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) )
- #if( defined( __DEBUGGING__ ) )
- #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED 1
- #else
- #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED 0
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DebugOutputType
-
- @abstract Type of debug output (i.e. where the output goes).
-*/
-
-typedef uint32_t DebugOutputType;
-
-#define kDebugOutputTypeNone 0x6E6F6E65U // 'none' - no params
-#define kDebugOutputTypeCustom 0x63757374U // 'cust' - 1st param = function ptr, 2nd param = context
-#define kDebugOutputTypeFPrintF 0x66707269U // 'fpri' - 1st param = DebugOutputTypeFlags [, 2nd param = filename]
-#define kDebugOutputTypeiDebug 0x69646267U // 'idbg' - no params
-#define kDebugOutputTypeKPrintF 0x6B707266U // 'kprf' - no params
-#define kDebugOutputTypeMacOSXIOLog 0x696C6F67U // 'ilog' - no params
-#define kDebugOutputTypeMacOSXLog 0x786C6F67U // 'xlog' - no params
-#define kDebugOutputTypeWindowsDebugger 0x77696E64U // 'wind' - no params
-#define kDebugOutputTypeWindowsEventLog 0x7765766CU // 'wevl' - 1st param = C-string name, 2nd param = HMODULE or NULL.
-
-// Console meta output kind - Any kind of Console output (in horizontal order of preference):
-//
-// Mac OS X = ANSI printf (viewable in Console.app)
-// Mac OS X Kernel = IOLog (/var/log/system.log) or kprintf (serial).
-// Windows = ANSI printf (Console window) or OutputDebugString (debugger).
-// Other = ANSI printf (viewer varies).
-
-#define kDebugOutputTypeMetaConsole 0x434F4E53U // 'CONS' - no params
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DebugOutputTypeFlags
-
- @abstract Flags controlling how the output type is configured.
-
- @constant kDebugOutputTypeFlagsTypeMask Bit mask for the output type (e.g. stdout, stderr, file, etc.).
- @constant kDebugOutputTypeFlagsStdOut fprintf should go to stdout.
- @constant kDebugOutputTypeFlagsStdErr fprintf should go to stderr.
- @constant kDebugOutputTypeFlagsFile fprintf should go to a specific file (filename passed as va_arg).
-*/
-
-typedef unsigned int DebugOutputTypeFlags;
-
-#define kDebugOutputTypeFlagsTypeMask 0xF
-#define kDebugOutputTypeFlagsStdOut 1
-#define kDebugOutputTypeFlagsStdErr 2
-#define kDebugOutputTypeFlagsFile 10
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DebugOutputFunctionPtr
-
- @abstract Function ptr for a custom callback to print debug output.
-*/
-
-typedef void ( *DebugOutputFunctionPtr )( char *inData, size_t inSize, void *inContext );
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#if 0
-#pragma mark == Flags ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DebugFlags
-
- @abstract Flags controlling how output is printed.
-*/
-
-typedef uint32_t DebugFlags;
-
-#define kDebugFlagsNone 0
-#define kDebugFlagsNoAddress ( 1 << 0 )
-#define kDebugFlagsNoOffset ( 1 << 1 )
-#define kDebugFlags32BitOffset ( 1 << 2 )
-#define kDebugFlagsNoASCII ( 1 << 3 )
-#define kDebugFlagsNoNewLine ( 1 << 4 )
-#define kDebugFlags8BitSeparator ( 1 << 5 )
-#define kDebugFlags16BitSeparator ( 1 << 6 )
-#define kDebugFlagsNo32BitSeparator ( 1 << 7 )
-#define kDebugFlagsNo16ByteHexPad ( 1 << 8 )
-#define kDebugFlagsNoByteCount ( 1 << 9 )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @enum DebugTaskLevelFlags
-
- @abstract Flags indicating the task level.
-*/
-
-enum
-{
- kDebugInterruptLevelShift = 0,
- kDebugInterruptLevelMask = 0x00000007,
- kDebugInVBLTaskMask = 0x00000010,
- kDebugInDeferredTaskMask = 0x00000020,
- kDebugInSecondaryInterruptHandlerMask = 0x00000040,
- kDebugPageFaultFatalMask = 0x00000100, // There should be a "kPageFaultFatalMask" in Debugging.h.
- kDebugMPTaskLevelMask = 0x00000200, // There should be a "kMPTaskLevelMask" in Debugging.h.
- kDebugInterruptDepthShift = 16,
- kDebugInterruptDepthMask = 0x00FF0000
-};
-
-#define DebugExtractTaskLevelInterruptLevel( LEVEL ) \
- ( ( ( LEVEL ) & kDebugInterruptLevelMask ) >> kDebugInterruptLevelShift )
-
-#define DebugExtractTaskLevelInterruptDepth( LEVEL ) \
- ( ( ( LEVEL ) & kDebugInterruptDepthMask ) >> kDebugInterruptDepthShift )
-
-#if 0
-#pragma mark == Levels ==
-#endif
-
-//===========================================================================================================================
-// Constants & Types - Levels
-//===========================================================================================================================
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DebugLevel
-
- @abstract Level used to control debug logging.
-*/
-
-typedef int32_t DebugLevel;
-
-// Levels
-
-#define kDebugLevelMask 0x0000FFFF
-#define kDebugLevelChatty 100
-#define kDebugLevelVerbose 500
-#define kDebugLevelTrace 800
-#define kDebugLevelInfo 1000
-#define kDebugLevelNotice 3000
-#define kDebugLevelWarning 5000
-#define kDebugLevelAssert 6000
-#define kDebugLevelRequire 7000
-#define kDebugLevelError 8000
-#define kDebugLevelCritical 9000
-#define kDebugLevelAlert 10000
-#define kDebugLevelEmergency 11000
-#define kDebugLevelTragic 12000
-#define kDebugLevelMax 0x0000FFFF
-
-// Level Flags
-
-#define kDebugLevelFlagMask 0xFFFF0000
-#define kDebugLevelFlagStackTrace 0x00010000
-#define kDebugLevelFlagDebugBreak 0x00020000
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef LogLevel
-
- @abstract Level used to control which events are logged.
-*/
-
-typedef int32_t LogLevel;
-
-#define kLogLevelUninitialized -1L
-#define kLogLevelAll 0L
-#define kLogLevelChatty 100L
-#define kLogLevelVerbose 500L
-#define kLogLevelTrace 800L
-#define kLogLevelInfo 1000L
-#define kLogLevelNotice 3000L
-#define kLogLevelWarning 4000L
-#define kLogLevelAssert 6000L
-#define kLogLevelRequire 7000L
-#define kLogLevelError 8000L
-#define kLogLevelCritical 9000L
-#define kLogLevelAlert 10000L
-#define kLogLevelEmergency 11000L
-#define kLogLevelTragic 12000L
-#define kLogLevelOff 0x0000FFFEL
-
-#if 0
-#pragma mark == Properties ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef DebugPropertyTag
-
- @abstract Tag for properties.
-*/
-
-typedef uint32_t DebugPropertyTag;
-
-#define kDebugPropertyTagPrintLevelMin 0x6D696E70U // 'minp' Get: 1st param = DebugLevel *
- // Set: 1st param = DebugLevel
-
-#define kDebugPropertyTagPrintLevel kDebugPropertyTagPrintLevelMin
-
-#define kDebugPropertyTagPrintLevelMax 0x706D786CU // 'maxp' Get: 1st param = DebugLevel *
- // Set: 1st param = DebugLevel
-
-#define kDebugPropertyTagBreakLevel 0x62726B6CU // 'brkl' Get: 1st param = DebugLevel *
- // Set: 1st param = DebugLevel
-#if 0
-#pragma mark == General macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_UNUSED
-
- @abstract Macro to mark a paramter as unused to avoid unused parameter warnings.
-
- @discussion
-
- There is no universally supported pragma/attribute for indicating a variable is unused. DEBUG_UNUSED lets us
- indicate a variable is unused in a manner that is supported by most compilers.
-*/
-
-#define DEBUG_UNUSED( X ) (void)( X )
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_USE_ONLY
-
- @abstract Macro to mark a variable as used only when debugging is enabled.
-
- @discussion
-
- Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables generate
- compiler warnings about unused variables. To eliminate these warnings, use these macros to indicate variables that
- are only used for debugging.
-*/
-
-#if( DEBUG )
- #define DEBUG_USE_ONLY( X )
-#else
- #define DEBUG_USE_ONLY( X ) (void)( X )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_LOCAL
-
- @abstract Macros to make variables and functions static when debugging is off, but extern when debugging is on.
-
- @discussion
-
- Rather than using "static" directly, using this macros allows you to access these variables external while
- debugging without being penalized for production builds.
-*/
-
-#if( DEBUG )
- #define DEBUG_LOCAL
-#else
- #define DEBUG_LOCAL static
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_STATIC
-
- @abstract Macros to make variables and functions static when debugging is off, but extern when debugging is on.
-
- @discussion
-
- Rather than using "static" directly, using this macros allows you to access these variables external while
- debugging without being penalized for production builds.
-*/
-
-#if( DEBUG )
- #define DEBUG_STATIC
-#else
- #define DEBUG_STATIC static
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DEBUG_EXPORT
-
- @abstract Macros to export variables.
-
- @discussion
-
- "__private_extern__" is a hack for IOKit to allow symbols to be exported from compilation units, but
- // not exported outside a driver (IOKit uses a lame global namespace for symbols). This still does not
- // solve the problem of multiple drivers in the same dependency chain since they share symbols.
-*/
-
-#if( TARGET_API_MAC_OSX_KERNEL )
- #define DEBUG_EXPORT __private_extern__
-#else
- #define DEBUG_EXPORT extern
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined debug_add
-
- @abstract Macro to add (or subtract if negative) a value when debugging is on. Does nothing if debugging is off.
-*/
-
-#if( DEBUG )
- #define debug_add( A, B ) ( A ) += ( B )
-#else
- #define debug_add( A, B )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined debug_perform
-
- @abstract Macro to perform something in debug-only builds.
-*/
-
-#if( DEBUG )
- #define debug_perform( X ) do { X; } while( 0 )
-#else
- #define debug_perform( X )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function translate_errno
-
- @abstract Returns 0 if the test success. If the test fails, returns errno if non-zero and othewise the alternate error.
-*/
-
-#define translate_errno( TEST, ERRNO, ALTERNATE_ERROR ) ( ( TEST ) ? 0 : ( ERRNO ) ? ( ERRNO ) : ( ALTERNATE_ERROR ) )
-
-#if 0
-#pragma mark == Compile Time macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined check_compile_time
-
- @abstract Performs a compile-time check of something such as the size of an int.
-
- @discussion
-
- This declares an array with a size that is determined by a compile-time expression. If the expression evaluates
- to 0, the array has a size of -1, which is illegal and generates a compile-time error.
-
- For example:
-
- check_compile_time( sizeof( int ) == 4 );
-
- Note: This only works with compile-time expressions.
- Note: This only works in places where extern declarations are allowed (e.g. global scope).
-
- References:
-
- <http://www.jaggersoft.com/pubs/CVu11_3.html>
- <http://www.jaggersoft.com/pubs/CVu11_5.html>
-
- Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not
- work with GCC due to GCC allow a zero-length array. Using a -1 condition turned out to be more portable.
-*/
-
-#define check_compile_time( X ) extern int debug_compile_time_name[ ( X ) ? 1 : -1 ]
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined check_compile_time_code
-
- @abstract Perform a compile-time check, suitable for placement in code, of something such as the size of an int.
-
- @discussion
-
- This creates a switch statement with an existing case for 0 and an additional case using the result of a
- compile-time expression. A switch statement cannot have two case labels with the same constant so if the
- compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time
- expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error.
-
- For example:
-
- check_compile_time_code( sizeof( int ) == 4 );
-
- Note: This only works with compile-time expressions.
- Note: This does not work in a global scope so it must be inside a function.
-
- References:
-
- <http://www.jaggersoft.com/pubs/CVu11_3.html>
- <http://www.jaggersoft.com/pubs/CVu11_5.html>
-*/
-
-#define check_compile_time_code( X ) switch( 0 ) { case 0: case X:; }
-
-#if 0
-#pragma mark == check macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined check
-
- @abstract Check that an expression is true (non-zero).
-
- @discussion
-
- If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
- function name, etc.) using the default debugging output method.
-
- Code inside check() statements is not compiled into production builds.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef check
-#endif
-#if( !defined( check ) )
- #if( DEBUG )
- #define check( X ) \
- do \
- { \
- if( !( X ) ) \
- { \
- debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
- } \
- } while( 0 )
- #else
- #define check( X )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined check_string
-
- @abstract Check that an expression is true (non-zero) with an explanation.
-
- @discussion
-
- If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
- function name, etc.) and a custom explanation string using the default debugging output method.
-
- Code inside check_string() statements is not compiled into production builds.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef check_string
-#endif
-#if( !defined( check_string ) )
- #if( DEBUG )
- #define check_string( X, STR ) \
- do \
- { \
- if( !( X ) ) \
- { \
- debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
- } \
- \
- } while( 0 )
- #else
- #define check_string( X, STR )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined check_noerr
-
- @abstract Check that an error code is noErr (0).
-
- @discussion
-
- If the error code is non-0, this prints debugging information (actual expression string, file, line number,
- function name, etc.) using the default debugging output method.
-
- Code inside check_noerr() statements is not compiled into production builds.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef check_noerr
-#endif
-#if( !defined( check_noerr ) )
- #if( DEBUG )
- #define check_noerr( ERR ) \
- do \
- { \
- int_least32_t localErr; \
- \
- localErr = (int_least32_t)( ERR ); \
- if( localErr != 0 ) \
- { \
- debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
- } \
- \
- } while( 0 )
- #else
- #define check_noerr( ERR )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined check_noerr_string
-
- @abstract Check that an error code is noErr (0) with an explanation.
-
- @discussion
-
- If the error code is non-0, this prints debugging information (actual expression string, file, line number,
- function name, etc.) and a custom explanation string using the default debugging output method.
-
- Code inside check_noerr_string() statements is not compiled into production builds.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef check_noerr_string
-#endif
-#if( !defined( check_noerr_string ) )
- #if( DEBUG )
- #define check_noerr_string( ERR, STR ) \
- do \
- { \
- int_least32_t localErr; \
- \
- localErr = (int_least32_t)( ERR ); \
- if( localErr != 0 ) \
- { \
- debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
- } \
- \
- } while( 0 )
- #else
- #define check_noerr_string( ERR, STR )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined check_translated_errno
-
- @abstract Check a condition and prints errno (if non-zero) to the log.
-
- @discussion
-
- Code inside check_translated_errno() statements is not compiled into production builds.
-*/
-
-#if( !defined( check_translated_errno ) )
- #if( DEBUG )
- #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) \
- do \
- { \
- if( !( TEST ) ) \
- { \
- int_least32_t localErr; \
- \
- localErr = (int_least32_t)( ERRNO ); \
- localErr = ( localErr != 0 ) ? localErr : (int_least32_t)( ALTERNATE_ERROR ); \
- debug_print_assert( localErr, #TEST, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
- } \
- \
- } while( 0 )
- #else
- #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined check_ptr_overlap
-
- @abstract Checks that two ptrs do not overlap.
-*/
-
-#define check_ptr_overlap( P1, P1_SIZE, P2, P2_SIZE ) \
- do \
- { \
- check( !( ( (uintptr_t)( P1 ) >= (uintptr_t)( P2 ) ) && \
- ( (uintptr_t)( P1 ) < ( ( (uintptr_t)( P2 ) ) + ( P2_SIZE ) ) ) ) ); \
- check( !( ( (uintptr_t)( P2 ) >= (uintptr_t)( P1 ) ) && \
- ( (uintptr_t)( P2 ) < ( ( (uintptr_t)( P1 ) ) + ( P1_SIZE ) ) ) ) ); \
- \
- } while( 0 )
-
-#if 0
-#pragma mark == require macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require
-
- @abstract Requires that an expression evaluate to true.
-
- @discussion
-
- If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
- function name, etc.) using the default debugging output method then jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require
-#endif
-#if( !defined( require ) )
- #define require( X, LABEL ) \
- do \
- { \
- if( !( X ) ) \
- { \
- debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_string
-
- @abstract Requires that an expression evaluate to true with an explanation.
-
- @discussion
-
- If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
- function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_string
-#endif
-#if( !defined( require_string ) )
- #define require_string( X, LABEL, STR ) \
- do \
- { \
- if( !( X ) ) \
- { \
- debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_quiet
-
- @abstract Requires that an expression evaluate to true.
-
- @discussion
-
- If expression evalulates to false, this jumps to a label. No debugging information is printed.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_quiet
-#endif
-#if( !defined( require_quiet ) )
- #define require_quiet( X, LABEL ) \
- do \
- { \
- if( !( X ) ) \
- { \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_noerr
-
- @abstract Require that an error code is noErr (0).
-
- @discussion
-
- If the error code is non-0, this prints debugging information (actual expression string, file, line number,
- function name, etc.) using the default debugging output method then jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_noerr
-#endif
-#if( !defined( require_noerr ) )
- #define require_noerr( ERR, LABEL ) \
- do \
- { \
- int_least32_t localErr; \
- \
- localErr = (int_least32_t)( ERR ); \
- if( localErr != 0 ) \
- { \
- debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_noerr_string
-
- @abstract Require that an error code is noErr (0).
-
- @discussion
-
- If the error code is non-0, this prints debugging information (actual expression string, file, line number,
- function name, etc.), and a custom explanation string using the default debugging output method using the
- default debugging output method then jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_noerr_string
-#endif
-#if( !defined( require_noerr_string ) )
- #define require_noerr_string( ERR, LABEL, STR ) \
- do \
- { \
- int_least32_t localErr; \
- \
- localErr = (int_least32_t)( ERR ); \
- if( localErr != 0 ) \
- { \
- debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_noerr_action_string
-
- @abstract Require that an error code is noErr (0).
-
- @discussion
-
- If the error code is non-0, this prints debugging information (actual expression string, file, line number,
- function name, etc.), and a custom explanation string using the default debugging output method using the
- default debugging output method then executes an action and jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_noerr_action_string
-#endif
-#if( !defined( require_noerr_action_string ) )
- #define require_noerr_action_string( ERR, LABEL, ACTION, STR ) \
- do \
- { \
- int_least32_t localErr; \
- \
- localErr = (int_least32_t)( ERR ); \
- if( localErr != 0 ) \
- { \
- debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
- { ACTION; } \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_noerr_quiet
-
- @abstract Require that an error code is noErr (0).
-
- @discussion
-
- If the error code is non-0, this jumps to a label. No debugging information is printed.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_noerr_quiet
-#endif
-#if( !defined( require_noerr_quiet ) )
- #define require_noerr_quiet( ERR, LABEL ) \
- do \
- { \
- if( ( ERR ) != 0 ) \
- { \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_noerr_action
-
- @abstract Require that an error code is noErr (0) with an action to execute otherwise.
-
- @discussion
-
- If the error code is non-0, this prints debugging information (actual expression string, file, line number,
- function name, etc.) using the default debugging output method then executes an action and jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_noerr_action
-#endif
-#if( !defined( require_noerr_action ) )
- #define require_noerr_action( ERR, LABEL, ACTION ) \
- do \
- { \
- int_least32_t localErr; \
- \
- localErr = (int_least32_t)( ERR ); \
- if( localErr != 0 ) \
- { \
- debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
- { ACTION; } \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_noerr_action_quiet
-
- @abstract Require that an error code is noErr (0) with an action to execute otherwise.
-
- @discussion
-
- If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_noerr_action_quiet
-#endif
-#if( !defined( require_noerr_action_quiet ) )
- #define require_noerr_action_quiet( ERR, LABEL, ACTION ) \
- do \
- { \
- if( ( ERR ) != 0 ) \
- { \
- { ACTION; } \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_action
-
- @abstract Requires that an expression evaluate to true with an action to execute otherwise.
-
- @discussion
-
- If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
- function name, etc.) using the default debugging output method then executes an action and jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_action
-#endif
-#if( !defined( require_action ) )
- #define require_action( X, LABEL, ACTION ) \
- do \
- { \
- if( !( X ) ) \
- { \
- debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
- { ACTION; } \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_action_quiet
-
- @abstract Requires that an expression evaluate to true with an action to execute otherwise.
-
- @discussion
-
- If expression evalulates to false, this executes an action and jumps to a label. No debugging information is printed.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_action_quiet
-#endif
-#if( !defined( require_action_quiet ) )
- #define require_action_quiet( X, LABEL, ACTION ) \
- do \
- { \
- if( !( X ) ) \
- { \
- { ACTION; } \
- goto LABEL; \
- } \
- \
- } while( 0 )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_action_string
-
- @abstract Requires that an expression evaluate to true with an explanation and action to execute otherwise.
-
- @discussion
-
- If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
- function name, etc.) and a custom explanation string using the default debugging output method then executes an
- action and jumps to a label.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef require_action_string
-#endif
-#if( !defined( require_action_string ) )
- #define require_action_string( X, LABEL, ACTION, STR ) \
- do \
- { \
- if( !( X ) ) \
- { \
- debug_print_assert( 0, #X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
- { ACTION; } \
- goto LABEL; \
- } \
- \
- } while( 0 )
-
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined require_throw
-
- @abstract Requires that an expression evaluates to true or an exception is thrown.
-
- @discussion
-
- If the expression evaluates to false, this prints debugging information (actual expression string, file,
- line number, function name, etc.) using the default debugging output method then throws an exception.
-*/
-
-#if( defined( __cplusplus ) )
- #define require_throw( X ) \
- do \
- { \
- if( !( X ) ) \
- { \
- debug_print_assert( 0, #X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
- throw kUnknownErr; \
- } \
- \
- } while( 0 )
-#endif
-
-#if 0
-#pragma mark == Design-By-Contract macros ==
-#endif
-
-//===========================================================================================================================
-// Design-By-Contract macros
-//===========================================================================================================================
-
-#define ensure( X ) check( X )
-#define ensure_string( X, STR ) check_string( X, STR )
-#define ensure_noerr( ERR ) check_noerr( ERR )
-#define ensure_noerr_string( ERR, STR ) check_noerr_string( ERR, STR )
-#define ensure_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
-
-// Note: Design-By-Contract "require" macros are already defined elsewhere.
-
-#if 0
-#pragma mark == Expect macros ==
-#endif
-
-//===========================================================================================================================
-// Expect macros
-//===========================================================================================================================
-
-// Expect macros allow code to include runtime checking of things that should not happen in shipping code (e.g. internal
-// programmer errors, such as a NULL parameter where it is not allowed). Once the code has been verified to work correctly
-// without asserting, the DEBUG_EXPECT_VERIFIED conditional can be set to eliminate the error checking entirely. It can
-// also be useful to measure the cost of error checking code by profiling with it enable and with it disabled.
-
-#if( DEBUG_EXPECT_VERIFIED )
- #define require_expect
- #define require_string_expect
- #define require_quiet_expect
- #define require_noerr_expect
- #define require_noerr_string_expect
- #define require_noerr_action_string_expect
- #define require_noerr_quiet_expect
- #define require_noerr_action_expect
- #define require_noerr_action_quiet_expect
- #define require_action_expect
- #define require_action_quiet_expect
- #define require_action_string_expect
-#else
- #define require_expect require
- #define require_string_expect require_string
- #define require_quiet_expect require_quiet
- #define require_noerr_expect require_noerr
- #define require_noerr_string_expect require_noerr_string
- #define require_noerr_action_string_expect require_noerr_action_string
- #define require_noerr_quiet_expect require_noerr_quiet
- #define require_noerr_action_expect require_noerr_action
- #define require_noerr_action_quiet_expect require_noerr_action_quiet
- #define require_action_expect require_action
- #define require_action_quiet_expect require_action_quiet
- #define require_action_string_expect require_action_string
-#endif
-
-#if 0
-#pragma mark == Output macros ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined debug_string
-
- @abstract Prints a debugging C string.
-*/
-
-#if( DEBUG_OVERRIDE_APPLE_MACROS )
- #undef debug_string
-#endif
-#if( !defined( debug_string ) )
- #if( DEBUG )
- #define debug_string( STR ) \
- do \
- { \
- debug_print_assert( 0, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
- \
- } while( 0 )
- #else
- #define debug_string( STR )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined debug_print_assert
-
- @abstract Prints an assertion.
-*/
-
-#if( DEBUG )
- #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION ) \
- DebugPrintAssert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
-#else
- #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined dlog
-
- @abstract Prints a debug-only message.
-*/
-
-#if( DEBUG )
- #if( DEBUG_C99_VA_ARGS )
- #define dlog( ... ) DebugPrintF( __VA_ARGS__ )
- #elif( DEBUG_GNU_VA_ARGS )
- #define dlog( ARGS... ) DebugPrintF( ## ARGS )
- #else
- #define dlog DebugPrintF
- #endif
-#else
- #if( DEBUG_C99_VA_ARGS )
- #define dlog( ... )
- #elif( DEBUG_GNU_VA_ARGS )
- #define dlog( ARGS... )
- #else
- #define dlog while( 0 )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined dlogv
-
- @abstract Prints a debug-only message.
-*/
-
-#if( DEBUG )
- #define dlogv( LEVEL, FORMAT, LIST ) DebugPrintFVAList( ( LEVEL ), ( FORMAT ), ( LIST ) )
-#else
- #define dlogv( LEVEL, FORMAT, LIST )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined dlogmem
-
- @abstract Prints a debug-only dump of memory.
-*/
-
-#if( DEBUG )
- #define dlogmem( LEVEL, PTR, SIZE ) \
- DebugHexDump( ( LEVEL ), 0, NULL, 0, 0, NULL, 0, ( PTR ), ( PTR ), ( SIZE ), kDebugFlagsNone, NULL, 0 )
-#else
- #define dlogmem( LEVEL, PTR, SIZE )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DebugNSLog
-
- @abstract Debug-only macro for the Cocoa NSLog function.
-*/
-
-#if( DEBUG )
- #if( DEBUG_C99_VA_ARGS )
- #define DebugNSLog( ... ) NSLog( __VA_ARGS__ )
- #elif( DEBUG_GNU_VA_ARGS )
- #define DebugNSLog( ARGS... ) NSLog( ## ARGS )
- #else
- #define DebugNSLog NSLog
- #endif
-#else
- #if( DEBUG_C99_VA_ARGS )
- #define DebugNSLog( ... )
- #elif( DEBUG_GNU_VA_ARGS )
- #define DebugNSLog( ARGS... )
- #else
- #define DebugNSLog while( 0 )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DebugLogMsg
-
- @abstract Debug-only macro for the VxWorks logMsg function.
-*/
-
-#if( TARGET_OS_VXWORKS )
- #if( DEBUG )
- #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 ) \
- do \
- { \
- if( ( inLevel >= gDebugPrintLevelMin ) || ( inLevel <= gDebugPrintLevelMax ) ) \
- { \
- logMsg( ( FORMAT ), ( P1 ), ( P2 ), ( P3 ), ( P4 ), ( P5 ), ( P6 ) ); \
- } \
- \
- } while( 0 )
- #else
- #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )
- #endif
-#else
- #define DebugLogMsg dlog
-#endif
-
-#if 0
-#pragma mark == Routines - General ==
-#endif
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugInitialize
-
- @abstract Initializes the debugging library for a specific kind of output.
-
- @param inType
- @param varArg Variable number parameters, controlled by the "inType" parameter.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... );
-#endif
-
-#if( DEBUG )
- #if( DEBUG_C99_VA_ARGS )
- #define debug_initialize( ... ) DebugInitialize( __VA_ARGS__ )
- #elif( DEBUG_GNU_VA_ARGS )
- #define debug_initialize( ARGS... ) DebugInitialize( ## ARGS )
- #else
- #define debug_initialize DebugInitialize
- #endif
-#else
- #if( DEBUG_C99_VA_ARGS )
- #define debug_initialize( ... )
- #elif( DEBUG_GNU_VA_ARGS )
- #define debug_initialize( ARGS... )
- #else
- #define debug_initialize while( 0 )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugFinalize
-
- @abstract Releases any resources used by the debugging library
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT void DebugFinalize( void );
-#endif
-
-#if( DEBUG )
- #define debug_terminate() DebugFinalize()
-#else
- #define debug_terminate()
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugGetProperty
-
- @abstract Gets the specified property from the debugging library.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... );
-#endif
-
-#if( DEBUG )
- #if( DEBUG_C99_VA_ARGS )
- #define debug_get_property( ... ) DebugGetProperty( __VA_ARGS__ )
- #elif( DEBUG_GNU_VA_ARGS )
- #define debug_get_property( ARGS... ) DebugGetProperty( ## ARGS )
- #else
- #define debug_get_property DebugGetProperty
- #endif
-#else
- #if( DEBUG_C99_VA_ARGS )
- #define debug_get_property( ... )
- #elif( DEBUG_GNU_VA_ARGS )
- #define debug_get_property( ARGS... )
- #else
- #define debug_get_property while( 0 )
- #endif
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugSetProperty
-
- @abstract Sets the specified property from the debugging library.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... );
-#endif
-
-#if( DEBUG )
- #if( DEBUG_C99_VA_ARGS )
- #define debug_set_property( ... ) DebugSetProperty( __VA_ARGS__ )
- #elif( DEBUG_GNU_VA_ARGS )
- #define debug_set_property( ARGS... ) DebugSetProperty( ## ARGS )
- #else
- #define debug_set_property DebugSetProperty
- #endif
-#else
- #if( DEBUG_C99_VA_ARGS )
- #define debug_set_property( ... )
- #elif( DEBUG_GNU_VA_ARGS )
- #define debug_set_property( ARGS... )
- #else
- #define debug_set_property while( 0 )
- #endif
-#endif
-
-#if 0
-#pragma mark == Routines - Debugging Output ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugPrintF
-
- @abstract Prints a debug message with printf-style formatting.
-
- @param inLevel Error that generated this assert or noErr.
-
- @param inFormatString
- C string containing assertion text.
-
- @param VAR_ARG
- Variable number of arguments depending on the format string.
-
- @result Number of bytes printed or -1 on error.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... );
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugPrintFVAList
-
- @abstract va_list version of DebugPrintF. See DebugPrintF for more info.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs );
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugPrintAssert
-
- @abstract Prints a message describing the reason the (e.g. an assert failed), an optional error message,
- an optional source filename, an optional source line number.
-
- @param inErrorCode Error that generated this assert or noErr.
- @param inAssertString C string containing assertion text.
- @param inMessage C string containing a message about the assert.
- @param inFileName C string containing path of file where the error occurred.
- @param inLineNumber Line number in source file where the error occurred.
- @param inFunction C string containing name of function where assert occurred.
-
- @discussion
-
- Example output:
-
- [ASSERT] assert: "dataPtr != NULL" allocate memory for object failed
- [ASSERT] where: "MyFile.c", line 123, ("MyFunction")
-
- OR
-
- [ASSERT] error: -6728 (kNoMemoryErr)
- [ASSERT] where: "MyFile.c", line 123, ("MyFunction")
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT void
- DebugPrintAssert(
- int_least32_t inErrorCode,
- const char * inAssertString,
- const char * inMessage,
- const char * inFilename,
- int_least32_t inLineNumber,
- const char * inFunction );
-#endif
-
-#if 0
-#pragma mark == Routines - Utilities ==
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugSNPrintF
-
- @abstract Debugging versions of standard C snprintf with extra features.
-
- @param sbuffer Buffer to receive result. Null terminated unless the buffer size is 0.
- @param buflen Size of the buffer including space for the null terminator.
- @param fmt printf-style format string.
- @param VAR_ARG Variable number of arguments depending on the format string.
-
- @result Number of characters written (minus the null terminator).
-
- @discussion
-
- Extra features over the standard C snprintf:
- <pre>
- 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
- %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
- %a - Network Address: %.4a=IPv4, %.6a=Ethernet, %.8a Fibre Channel, %.16a=IPv6. Arg=ptr to network address.
- %#a - IPv4 or IPv6 mDNSAddr. Arg=ptr to mDNSAddr.
- %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
- %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
- %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
- %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
- %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
- %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code arg=the same as %d, %x, etc.
- %#s - Pascal-style length-prefixed string. Arg=ptr to string.
- %##s - DNS label-sequence name. Arg=ptr to name.
- %S - UTF-16 string, 0x0000 terminated. Host order if no BOM. Precision is UTF-16 count. Precision includes BOM.
- %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
- %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
- %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
- </pre>
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...);
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugSNPrintFVAList
-
- @abstract va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg);
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugGetErrorString
-
- @abstract Gets an error string from an error code.
-
- @param inStatus Error code to get the string for.
- @param inBuffer Optional buffer to copy the string to for non-static strings. May be null.
- @param inBufferSize Size of optional buffer. May be 0.
-
- @result C string containing error string for the error code. Guaranteed to be a valid, static string. If a
- buffer is supplied, the return value will always be a pointer to the supplied buffer, which will
- contain the best available description of the error code. If a buffer is not supplied, the return
- value will be the best available description of the error code that can be represented as a static
- string. This allows code that cannot use a temporary buffer to hold the result to still get a useful
- error string in most cases, but also allows code that can use a temporary buffer to get the best
- available description.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize );
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugHexDump
-
- @abstract Hex dumps data to a string or to the output device.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT size_t
- DebugHexDump(
- DebugLevel inLevel,
- int inIndent,
- const char * inLabel,
- size_t inLabelSize,
- int inLabelMinWidth,
- const char * inType,
- size_t inTypeSize,
- const void * inDataStart,
- const void * inData,
- size_t inDataSize,
- DebugFlags inFlags,
- char * outBuffer,
- size_t inBufferSize );
-#endif
-
-#if( DEBUG )
- #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE ) \
- DebugHexDump( ( LEVEL ), (INDENT), ( LABEL ), ( LABEL_SIZE ), ( LABEL_MIN_SIZE ), ( TYPE ), ( TYPE_SIZE ), \
- ( DATA_START ), ( DATA ), ( DATA_SIZE ), ( FLAGS ), ( BUFFER ), ( BUFFER_SIZE ) )
-#else
- #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugTaskLevel
-
- @abstract Returns the current task level.
-
- @result Current task level
-
- @discussion
-
- Bit masks to isolate portions of the result (note that some masks may also need bit shifts to right justify):
- <pre>
- kDebugInterruptLevelMask - Indicates the current interrupt level (> 0 means interrupt time).
- kDebugInVBLTaskMask - Indicates if a VBL task is currently being executed.
- kDebugInDeferredTaskMask - Indicates if a Deferred Task is currently being executed.
- kDebugInSecondaryInterruptHandlerMask - Indicates if a Secondary Interrupt Handler is currently being executed.
- kDebugPageFaultFatalMask - Indicates if it is unsafe to cause a page fault (worse than interrupt time).
- kDebugMPTaskLevelMask - Indicates if being called from an MP task.
- kDebugInterruptDepthMask - 0 means task level, 1 means in interrupt, > 1 means in nested interrupt.
- </pre>
-
- Helpers:
- <pre>
- DebugExtractTaskLevelInterruptDepth() - Macro to extract interrupt depth from task level value.
- </pre>
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT uint32_t DebugTaskLevel( void );
-#endif
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function DebugServicesTest
-
- @abstract Unit test.
-*/
-
-#if( DEBUG )
- DEBUG_EXPORT OSStatus DebugServicesTest( void );
-#endif
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif // __DEBUG_SERVICES__
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: jdns_sd.rc,v $
+Revision 1.5 2007/04/27 20:34:31 herscher
+<rdar://problem/5159673> mDNS: Company name needs to be changed to Apple Inc.
+
+Revision 1.4 2006/08/14 23:26:04 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2004/10/19 03:41:42 shersche
<rdar://problem/3843396> Include "afxres.h" to resource script so it gets compiled correctly
Bug #: 3843396
BEGIN
BLOCK "040904b0"
BEGIN
- VALUE "CompanyName", "Apple Computer, Inc."
+ VALUE "CompanyName", MASTER_COMPANY_NAME
VALUE "FileDescription", MASTER_PROD_NAME " support for Java"
VALUE "FileVersion", MASTER_PROD_VERS_STR
VALUE "InternalName", "jdns_sd"
- VALUE "LegalCopyright", "Copyright (C) 2004"
+ VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
VALUE "OriginalFilename", "jdns_sd.dll"
VALUE "ProductName", MASTER_PROD_NAME
VALUE "ProductVersion", MASTER_PROD_VERS_STR
+# -*- tab-width: 4 -*-
+#
# Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
#
-# @APPLE_LICENSE_HEADER_START@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# This file contains Original Code and/or Modifications of Original Code
-# as defined in and that are subject to the Apple Public Source License
-# Version 2.0 (the 'License'). You may not use this file except in
-# compliance with the License. Please obtain a copy of the License at
-# http://www.opensource.apple.com/apsl/ and read it before using this
-# file.
+# http://www.apache.org/licenses/LICENSE-2.0
#
-# The Original Code and all software distributed under the License are
-# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-# Please see the License for the specific language governing rights and
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
# limitations under the License.
-#
-# @APPLE_LICENSE_HEADER_END@
#
# $Log: makefile,v $
+# Revision 1.9 2006/08/14 23:26:04 cheshire
+# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+#
+# Revision 1.8 2006/07/05 20:57:22 cheshire
+# <rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+#
# Revision 1.7 2005/10/19 17:19:56 herscher
# Change JDK to use JAVA_HOME environment variable
#
$(OBJDIR)\com\apple\dnssd\RegisterListener.class \
$(OBJDIR)\com\apple\dnssd\QueryListener.class \
$(OBJDIR)\com\apple\dnssd\DomainListener.class \
+ $(OBJDIR)\com\apple\dnssd\DNSSDRecordRegistrar.class \
+ $(OBJDIR)\com\apple\dnssd\RegisterRecordListener.class \
$(OBJDIR)\com\apple\dnssd\DNSSD.class
$(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: NSPTool.c,v $
+Revision 1.4 2006/08/14 23:26:06 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2004/08/26 04:46:49 shersche
Add -q switch for silent operation
BEGIN\r
BLOCK "040904b0"\r
BEGIN\r
- VALUE "CompanyName", "Apple Computer, Inc."\r
+ VALUE "CompanyName", MASTER_COMPANY_NAME\r
VALUE "FileDescription", "NSPTool Application"\r
VALUE "FileVersion", MASTER_PROD_VERS_STR\r
VALUE "InternalName", "NSPTool"\r
<Tool\r
Name="VCCLCompilerTool"\r
Optimization="0"\r
- AdditionalIncludeDirectories=".;.."\r
+ AdditionalIncludeDirectories=".;../../mDNSShared"\r
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN"\r
StringPooling="TRUE"\r
MinimalRebuild="TRUE"\r
CharacterSet="2">\r
<Tool\r
Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=".;.."\r
+ AdditionalIncludeDirectories=".;../../mDNSShared"\r
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN"\r
RuntimeLibrary="0"\r
UsePrecompiledHeader="0"\r
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
<File\r
- RelativePath="..\DebugServices.c">\r
+ RelativePath="..\..\mDNSShared\DebugServices.c">\r
</File>\r
<File\r
RelativePath=".\NSPTool.c">\r
Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
<File\r
- RelativePath="..\CommonServices.h">\r
+ RelativePath="..\..\mDNSShared\CommonServices.h">\r
</File>\r
<File\r
- RelativePath="..\DebugServices.h">\r
+ RelativePath="..\..\mDNSShared\DebugServices.h">\r
</File>\r
<File\r
RelativePath=".\resource.h">\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Prefix.h,v $
+Revision 1.2 2006/08/14 23:26:06 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/06/18 04:14:26 rpantos
Move up one level.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: RegNames.h,v $
+Revision 1.3 2006/08/14 23:25:20 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.2 2005/10/05 18:05:28 herscher
<rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Firewall.cpp,v $
+Revision 1.4 2006/08/14 23:26:07 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.3 2005/09/29 06:33:54 herscher
<rdar://problem/4278931> Fix compilation error when using latest Microsoft Platform SDK.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Firewall.h,v $
+Revision 1.2 2006/08/14 23:26:07 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/09/13 07:32:31 shersche
Wrapper for Windows Firewall API code
-\r
-\r
-*/\r
-\r
-#ifndef _Firewall_h\r
-#define _Firewall_h\r
-\r
-\r
-#include "CommonServices.h"\r
-#include "DebugServices.h"\r
-\r
-\r
-#if defined(__cplusplus)\r
-extern "C"\r
-{\r
-#endif\r
-\r
-\r
-OSStatus\r
-mDNSAddToFirewall\r
- (\r
- LPWSTR executable,\r
- LPWSTR name\r
- );\r
-\r
-\r
-#if defined(__cplusplus)\r
-}\r
-#endif\r
-\r
-\r
-#endif\r
+
+
+
+
+*/
+
+
+
+#ifndef _Firewall_h
+
+#define _Firewall_h
+
+
+
+
+
+#include "CommonServices.h"
+
+#include "DebugServices.h"
+
+
+
+
+
+#if defined(__cplusplus)
+
+extern "C"
+
+{
+
+#endif
+
+
+
+
+
+OSStatus
+
+mDNSAddToFirewall
+
+ (
+
+ LPWSTR executable,
+
+ LPWSTR name
+
+ );
+
+
+
+
+
+#if defined(__cplusplus)
+
+}
+
+#endif
+
+
+
+
+
+#endif
+
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Prefix.h,v $
+Revision 1.2 2006/08/14 23:26:07 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/06/18 04:16:41 rpantos
Move up one level.
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Service.c,v $
+Revision 1.42 2007/02/14 01:58:19 cheshire
+<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
+
+Revision 1.41 2007/02/06 19:06:49 cheshire
+<rdar://problem/3956518> Need to go native with launchd
+
+Revision 1.40 2007/01/05 05:46:08 cheshire
+Add mDNS *const m parameter to udsserver_handle_configchange()
+
+Revision 1.39 2006/08/14 23:26:07 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.38 2005/10/05 20:55:15 herscher
<rdar://problem/4096464> Don't call SetLLRoute on loopback interface
err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext);
require_noerr( err, exit);
- err = udsserver_init();
+ err = udsserver_init(dnssd_InvalidSocket);
require_noerr( err, exit);
//
//
// give a chance for the udsserver code to clean up
//
- udsserver_exit();
+ udsserver_exit(dnssd_InvalidSocket);
//
// and finally close down the mDNSCore
{
DEBUG_UNUSED( inMDNS );
- udsserver_handle_configchange();
+ udsserver_handle_configchange(inMDNS);
}
BEGIN
BLOCK "040904b0"
BEGIN
- VALUE "CompanyName", "Apple Computer, Inc."
+ VALUE "CompanyName", MASTER_COMPANY_NAME
VALUE "FileDescription", "Bonjour Service"
VALUE "FileVersion", MASTER_PROD_VERS_STR
VALUE "InternalName", "mDNSResponder.exe"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
<File\r
- RelativePath="..\dDNS.c">\r
- </File>\r
- <File\r
- RelativePath="..\DebugServices.c">\r
+ RelativePath="..\..\mDNSShared\DebugServices.c">\r
</File>\r
<File\r
RelativePath="..\..\mDNSCore\DNSCommon.c">\r
Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
<File\r
- RelativePath="..\CommonServices.h">\r
- </File>\r
- <File\r
- RelativePath="..\dDNS.h">\r
+ RelativePath="..\..\mDNSShared\CommonServices.h">\r
</File>\r
<File\r
- RelativePath="..\DebugServices.h">\r
+ RelativePath="..\..\mDNSShared\DebugServices.h">\r
</File>\r
<File\r
RelativePath="..\..\mDNSCore\DNSCommon.h">\r
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: VPCDetect.cpp,v $
+Revision 1.3 2006/08/14 23:25:20 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.2 2006/02/26 19:31:05 herscher
+<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency. The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it. 2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
+
Revision 1.1 2005/11/27 20:21:16 herscher
<rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
static BOOL g_isVPC = FALSE;
-BOOL
-IsVPCRunning()
+mStatus
+IsVPCRunning( BOOL * inVirtualPC )
{
IWbemLocator * pLoc = 0;
IWbemServices * pSvc = 0;
IEnumWbemClassObject * pEnumerator = NULL;
bool coInit = false;
HRESULT hres;
-
- // Short circuit if we've already done this
-
- require_action_quiet( !g_doneCheck, exit, g_doneCheck = TRUE );
-
+ SC_HANDLE scm = NULL;
+ SC_HANDLE service = NULL;
+ SERVICE_STATUS status;
+ mStatus err;
+ BOOL ok = TRUE;
+
+ // Initialize flag
+
+ *inVirtualPC = FALSE;
+
+ // Find out if WMI is running
+
+ scm = OpenSCManager( 0, 0, SC_MANAGER_CONNECT );
+ err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
+ require_noerr( err, exit );
+
+ service = OpenService( scm, TEXT( "winmgmt" ), SERVICE_QUERY_STATUS );
+ err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
+ require_noerr( err, exit );
+
+ ok = QueryServiceStatus( service, &status );
+ err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
+ require_noerr( err, exit );
+ require_action( status.dwCurrentState == SERVICE_RUNNING, exit, err = kUnknownErr );
+
// Initialize COM.
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
- require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+ require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
coInit = true;
// Initialize Security
hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL );
- require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+ require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
// Obtain the initial locator to Windows Management on a particular host computer.
hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc );
- require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+ require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
// Connect to the root\cimv2 namespace with the
// current user and obtain pointer pSvc
// to make IWbemServices calls.
- hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc );
- require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+ hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, WBEM_FLAG_CONNECT_USE_MAX_WAIT, 0, 0, &pSvc );
+ require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
// Set the IWbemServices proxy so that impersonation
// of the user (client) occurs.
hres = CoSetProxyBlanket( pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
- require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+ require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
// Use the IWbemServices pointer to make requests of WMI.
// Make requests here:
hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * from Win32_BaseBoard"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
- require_action( SUCCEEDED( hres ), exit, g_isVPC = false );
+ require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
do
{
if (wcscmp( wstring, L"microsoft corporation" ) == 0 )
{
- g_isVPC = true;
+ *inVirtualPC = TRUE;
}
}
CoUninitialize();
}
- if ( !g_doneCheck )
+ if ( service )
{
- g_doneCheck = TRUE;
+ CloseServiceHandle( service );
+ }
- if ( g_isVPC )
- {
- dlog( kDebugLevelTrace, "Virtual PC detected" );
- }
+ if ( scm )
+ {
+ CloseServiceHandle( scm );
+ }
+
+ if ( *inVirtualPC )
+ {
+ dlog( kDebugLevelTrace, "Virtual PC detected" );
}
- return g_isVPC;
+ return err;
}
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: VPCDetect.h,v $
+Revision 1.3 2006/08/14 23:25:20 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.2 2006/02/26 19:31:05 herscher
+<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency. The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it. 2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
+
Revision 1.1 2005/11/27 20:21:16 herscher
<rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
#pragma once
#include <windows.h>
+#include <mDNSEmbeddedAPI.h>
#if defined(__cplusplus)
#endif
-extern BOOL
-IsVPCRunning();
+extern mStatus
+IsVPCRunning( BOOL * inVirtualPC );
#if defined(__cplusplus)
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: WinServices.cpp,v $
+Revision 1.2 2006/08/14 23:25:20 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/06/18 05:23:33 rpantos
First checked in
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: WinServices.h,v $
+Revision 1.2 2006/08/14 23:25:21 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
Revision 1.1 2004/06/18 05:23:33 rpantos
First checked in
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: WinVersRes.h,v $
+Revision 1.55 2007/04/27 20:34:31 herscher
+<rdar://problem/5159673> mDNS: Company name needs to be changed to Apple Inc.
+
+Revision 1.54 2006/08/14 23:25:21 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.53 2006/02/28 20:07:53 herscher
+Bump to 1.0.3.1
+
+Revision 1.52 2006/01/09 20:45:29 cheshire
+Update copyright date to 2006
+
Revision 1.51 2005/11/28 19:49:56 herscher
Bump to 1.0.2.9
#define MASTER_PROD_NAME "Bonjour"
+// Define the company name for mDNSResponder on Windows
+#define MASTER_COMPANY_NAME "Apple Inc."
+
// Define the product version for mDNSResponder on Windows
-#define MASTER_PROD_VERS 1,0,2,9
-#define MASTER_PROD_VERS_STR "1,0,2,9"
-#define MASTER_PROD_VERS_STR2 "1.0.2.9"
-#define MASTER_PROD_VERS_STR3 "Explorer Plugin 1.0.2.9"
+#define MASTER_PROD_VERS 1,0,3,1
+#define MASTER_PROD_VERS_STR "1,0,3,1"
+#define MASTER_PROD_VERS_STR2 "1.0.3.1"
+#define MASTER_PROD_VERS_STR3 "Explorer Plugin 1.0.3.1"
// Define the legal copyright
-#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2005 Apple Computer, Inc."
+#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2007 Apple Inc."
#endif // WINRESVERS_H
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: dDNS.c,v $
-Revision 1.8 2005/09/12 07:13:33 herscher
-<rdar://problem/4248878> Workaround for router crash. Lazily call RegisterSearchDomains rather than call it always at startup.
-
-Revision 1.7 2005/08/10 01:43:23 herscher
-Pass NULL in for the IPv6 paramter to mDNS_SetPrimaryInterfaceInfo to get this code to compile on Windows.
-
-Revision 1.6 2005/03/23 05:54:48 cheshire
-<rdar://problem/4021486> Fix build warnings
-Fix %s where it should be %##s in debugf & LogMsg calls
-
-*/
-
-#include "dDNS.h"
-#include "DNSCommon.h"
-#include "uds_daemon.h"
-#include <winsock2.h>
-#include <iphlpapi.h>
-#include <ws2tcpip.h>
-
-typedef struct SearchListElem
- {
- struct SearchListElem *next;
- domainname domain;
- int flag;
- DNSQuestion BrowseQ;
- DNSQuestion DefBrowseQ;
- DNSQuestion LegacyBrowseQ;
- DNSQuestion RegisterQ;
- DNSQuestion DefRegisterQ;
- ARListElem *AuthRecs;
- } SearchListElem;
-// for domain enumeration and default browsing/registration
-static SearchListElem *SearchList = mDNSNULL; // where we search for _browse domains
-static DNSQuestion LegacyBrowseDomainQ; // our local enumeration query for _legacy._browse domains
-static DNameListElem *DefBrowseList = mDNSNULL; // cache of answers to above query (where we search for empty string browses)
-static DNameListElem *DefRegList = mDNSNULL; // manually generated list of domains where we register for empty string registrations
-static ARListElem *SCPrefBrowseDomains = mDNSNULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
-
-static domainname dDNSRegDomain; // Default wide-area zone for service registration
-static DNameListElem * dDNSBrowseDomains; // Default wide-area zone for legacy ("empty string") browses
-static domainname dDNSHostname;
-static mDNSBool dDNSRegisterSearchDomains = mDNSfalse;
-
-mDNSlocal mStatus RegisterNameServers( mDNS *const m );
-mDNSlocal mStatus RegisterSearchDomains( mDNS *const m );
-
-
-mStatus dDNS_SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
- {
- if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
-
- if (sa->sa_family == AF_INET)
- {
- struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
- ip->type = mDNSAddrType_IPv4;
- ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
- return(mStatus_NoError);
- }
-
- if (sa->sa_family == AF_INET6)
- {
- struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
- ip->type = mDNSAddrType_IPv6;
-#if !defined(_WIN32)
- if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
-#else
- if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
-#endif
- ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
- return(mStatus_NoError);
- }
-
- LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
- return(mStatus_Invalid);
- }
-
-
-mStatus dDNS_RegisterSearchDomains( mDNS * const m )
- {
- mStatus err = mStatus_NoError;
-
- dDNSRegisterSearchDomains = mDNStrue;
- RegisterSearchDomains( m );
-
- return err;
- }
-
-
-mDNSlocal void MarkSearchListElem(domainname *domain)
- {
- SearchListElem *new, *ptr;
-
- // if domain is in list, mark as pre-existent (0)
- for (ptr = SearchList; ptr; ptr = ptr->next)
- if (SameDomainName(&ptr->domain, domain))
- {
- if (ptr->flag != 1) ptr->flag = 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
- break;
- }
-
- // if domain not in list, add to list, mark as add (1)
- if (!ptr)
- {
- new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
- if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
- bzero(new, sizeof(SearchListElem));
- AssignDomainName(&new->domain, domain);
- new->flag = 1; // add
- new->next = SearchList;
- SearchList = new;
- }
- }
-
-//!!!KRS here is where we will give success/failure notification to the UI
-mDNSlocal void SCPrefsdDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
- {
- (void)m; // unused
- debugf("SCPrefsdDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
- dDNSPlatformSetNameStatus(rr->resrec.name, result);
- }
-
-mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
- {
- ARListElem *elem = rr->RecordContext;
-
- (void)m; // unused
-
- if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
- }
-
-mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
- {
- SearchListElem *slElem = question->QuestionContext;
- ARListElem *arElem, *ptr, *prev;
- AuthRecord *dereg;
- const char *name;
- mStatus err;
-
- if (AddRecord)
- {
- arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
- if (!arElem) { LogMsg("ERROR: malloc"); return; }
- mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem);
- if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
- else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
- else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
- else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
- else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
- else { LogMsg("FoundDomain - unknown question"); return; }
-
- MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
- AppendDNSNameString (arElem->ar.resrec.name, "local");
- AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
- err = mDNS_Register(m, &arElem->ar);
- if (err)
- {
- LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
- freeL("FoundDomain - arElem", arElem);
- return;
- }
- arElem->next = slElem->AuthRecs;
- slElem->AuthRecs = arElem;
- }
- else
- {
- ptr = slElem->AuthRecs;
- prev = NULL;
- while (ptr)
- {
- if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
- {
- debugf("Deregistering PTR %##s -> %##s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
- dereg = &ptr->ar;
- if (prev) prev->next = ptr->next;
- else slElem->AuthRecs = ptr->next;
- ptr = ptr->next;
- err = mDNS_Deregister(m, dereg);
- if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
- }
- else
- {
- prev = ptr;
- ptr = ptr->next;
- }
- }
- }
- }
-
-mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
- {
- return mDNS_CopyDNameList(DefBrowseList);
- }
-
-mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
- {
- return mDNS_CopyDNameList(DefRegList);
- }
-
-mDNSlocal void AddDefRegDomain(domainname *d)
- {
- DNameListElem *newelem = NULL, *ptr;
-
- // make sure name not already in list
- for (ptr = DefRegList; ptr; ptr = ptr->next)
- {
- if (SameDomainName(&ptr->name, d))
- { debugf("duplicate addition of default reg domain %##s", d->c); return; }
- }
-
- newelem = mallocL("DNameListElem", sizeof(*newelem));
- if (!newelem) { LogMsg("Error - malloc"); return; }
- AssignDomainName(&newelem->name, d);
- newelem->next = DefRegList;
- DefRegList = newelem;
-
- dDNSPlatformDefaultRegDomainChanged(d, mDNStrue);
- udsserver_default_reg_domain_changed(d, mDNStrue);
- }
-
-mDNSlocal void RemoveDefRegDomain(domainname *d)
- {
- DNameListElem *ptr = DefRegList, *prev = NULL;
-
- while (ptr)
- {
- if (SameDomainName(&ptr->name, d))
- {
- if (prev) prev->next = ptr->next;
- else DefRegList = ptr->next;
- freeL("DNameListElem", ptr);
- dDNSPlatformDefaultRegDomainChanged(d, mDNSfalse);
- udsserver_default_reg_domain_changed(d, mDNSfalse);
- return;
- }
- prev = ptr;
- ptr = ptr->next;
- }
- debugf("Requested removal of default registration domain %##s not in contained in list", d->c);
- }
-
-
-mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
- {
- DNameListElem *ptr, *prev, *new;
- (void)m; // unused;
- (void)question; // unused
-
- if (AddRecord)
- {
- new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem));
- if (!new) { LogMsg("ERROR: malloc"); return; }
- AssignDomainName(&new->name, &answer->rdata->u.name);
- new->next = DefBrowseList;
- DefBrowseList = new;
- dDNSPlatformDefaultBrowseDomainChanged(&new->name, mDNStrue);
- udsserver_default_browse_domain_changed(&new->name, mDNStrue);
- return;
- }
- else
- {
- ptr = DefBrowseList;
- prev = NULL;
- while (ptr)
- {
- if (SameDomainName(&ptr->name, &answer->rdata->u.name))
- {
- dDNSPlatformDefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
- udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
- if (prev) prev->next = ptr->next;
- else DefBrowseList = ptr->next;
- freeL("FoundDefBrowseDomain", ptr);
- return;
- }
- prev = ptr;
- ptr = ptr->next;
- }
- LogMsg("FoundDefBrowseDomain: Got remove event for domain %##s not in list", answer->rdata->u.name.c);
- }
- }
-
-
-mDNSlocal mStatus RegisterNameServers( mDNS *const m )
- {
- IPAddrListElem * list;
- IPAddrListElem * elem;
-
- mDNS_DeleteDNSServers(m); // deregister orig list
-
- list = dDNSPlatformGetDNSServers();
-
- for ( elem = list; elem; elem = elem->next )
- {
- LogOperation("RegisterNameServers: Adding %#a", &elem->addr);
- mDNS_AddDNSServer(m, &elem->addr, NULL);
- }
-
- dDNS_FreeIPAddrList( list );
-
- return mStatus_NoError;
- }
-
-
-mDNSlocal mStatus RegisterSearchDomains( mDNS *const m )
- {
- SearchListElem *ptr, *prev, *freeSLPtr;
- DNameListElem * elem;
- DNameListElem * list;
- ARListElem *arList;
- mStatus err;
- mDNSBool dict = 1;
-
- // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
- for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
-
- // get all the domains from "Search Domains" field of sharing prefs
-
- list = dDNSPlatformGetSearchDomainList();
-
- for ( elem = list; elem; elem = elem->next )
- {
- MarkSearchListElem(&elem->name);
- }
-
- mDNS_FreeDNameList( list );
-
- list = dDNSPlatformGetDomainName();
-
- if ( list )
- {
- MarkSearchListElem( &list->name );
- mDNS_FreeDNameList( list );
- }
-
- list = dDNSPlatformGetReverseMapSearchDomainList( );
-
- for ( elem = list; elem; elem = elem->next )
- {
- MarkSearchListElem(&elem->name);
- }
-
- mDNS_FreeDNameList( list );
-
- if (dDNSRegDomain.c[0]) MarkSearchListElem(&dDNSRegDomain); // implicitly browse reg domain too (no-op if same as BrowseDomain)
-
- // delete elems marked for removal, do queries for elems marked add
- prev = mDNSNULL;
- ptr = SearchList;
- while (ptr)
- {
- if (ptr->flag == -1) // remove
- {
- mDNS_StopQuery(m, &ptr->BrowseQ);
- mDNS_StopQuery(m, &ptr->RegisterQ);
- mDNS_StopQuery(m, &ptr->DefBrowseQ);
- mDNS_StopQuery(m, &ptr->DefRegisterQ);
- mDNS_StopQuery(m, &ptr->LegacyBrowseQ);
-
- // deregister records generated from answers to the query
- arList = ptr->AuthRecs;
- ptr->AuthRecs = mDNSNULL;
- while (arList)
- {
- AuthRecord *dereg = &arList->ar;
- arList = arList->next;
- debugf("Deregistering PTR %##s -> %##s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c);
- err = mDNS_Deregister(m, dereg);
- if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
- }
-
- // remove elem from list, delete
- if (prev) prev->next = ptr->next;
- else SearchList = ptr->next;
- freeSLPtr = ptr;
- ptr = ptr->next;
- freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr);
- continue;
- }
-
- if (ptr->flag == 1) // add
- {
- mStatus err1, err2, err3, err4, err5;
- err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
- if (err1 || err2 || err3 || err4 || err5)
- LogMsg("GetDomains for domain %##s returned error(s):\n"
- "%d (mDNS_DomainTypeBrowse)\n"
- "%d (mDNS_DomainTypeBrowseDefault)\n"
- "%d (mDNS_DomainTypeRegistration)\n"
- "%d (mDNS_DomainTypeRegistrationDefault)"
- "%d (mDNS_DomainTypeBrowseLegacy)\n",
- ptr->domain.c, err1, err2, err3, err4, err5);
- ptr->flag = 0;
- }
-
- if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
-
- prev = ptr;
- ptr = ptr->next;
- }
-
- return mStatus_NoError;
- }
-
-
-mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
- {
- // allocate/register legacy and non-legacy _browse PTR record
- mStatus err;
- ARListElem *browse = mallocL("ARListElem", sizeof(*browse));
- mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, browse);
- MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]);
- AppendDNSNameString (browse->ar.resrec.name, "local");
- AssignDomainName(&browse->ar.resrec.rdata->u.name, d);
- err = mDNS_Register(m, &browse->ar);
- if (err)
- {
- LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
- freeL("ARListElem", browse);
- }
- else
- {
- browse->next = SCPrefBrowseDomains;
- SCPrefBrowseDomains = browse;
- }
- }
-
-mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
- {
- ARListElem *remove, **ptr = &SCPrefBrowseDomains;
- domainname lhs; // left-hand side of PTR, for comparison
-
- MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
- AppendDNSNameString (&lhs, "local");
-
- while (*ptr)
- {
- if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
- {
- remove = *ptr;
- *ptr = (*ptr)->next;
- mDNS_Deregister(m, &remove->ar);
- return;
- }
- else ptr = &(*ptr)->next;
- }
- }
-
-// Add or remove a user-specified domain to the list of empty-string browse domains
-// Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
-mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
- {
- LogMsg("%s default browse domain %##s", add ? "Adding" : "Removing", d->c);
-
- if (add)
- {
- RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
- RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
- }
- else
- {
- DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
- DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
- }
- }
-
-mDNSlocal void SetSCPrefsBrowseDomains(mDNS *m, DNameListElem * browseDomains, mDNSBool add)
- {
- DNameListElem * browseDomain;
-
- for ( browseDomain = browseDomains; browseDomain; browseDomain = browseDomain->next )
- {
- if ( !browseDomain->name.c[0] )
- {
- LogMsg("SetSCPrefsBrowseDomains bad DDNS browse domain: %##s", browseDomain->name.c[0] ? (char*) browseDomain->name.c : "(unknown)");
- }
- else
- {
- SetSCPrefsBrowseDomain(m, &browseDomain->name, add);
- }
- }
- }
-
-mStatus dDNS_Setup( mDNS *const m )
- {
- static mDNSBool LegacyNATInitialized = mDNSfalse;
- mDNSBool dict = mDNStrue;
- mDNSAddr ip;
- mDNSAddr r;
- DNameListElem * BrowseDomains;
- domainname RegDomain, fqdn;
-
- // get fqdn, zone from SCPrefs
- dDNSPlatformGetConfig(&fqdn, &RegDomain, &BrowseDomains);
-
- // YO if (!fqdn.c[0] && !RegDomain.c[0]) ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &fqdn, &RegDomain);
-
- if (!SameDomainName(&RegDomain, &dDNSRegDomain))
- {
- if (dDNSRegDomain.c[0])
- {
- RemoveDefRegDomain(&dDNSRegDomain);
- SetSCPrefsBrowseDomain(m, &dDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop
- }
-
- AssignDomainName(&dDNSRegDomain, &RegDomain);
-
- if (dDNSRegDomain.c[0])
- {
- dDNSPlatformSetSecretForDomain(m, &dDNSRegDomain);
- AddDefRegDomain(&dDNSRegDomain);
- SetSCPrefsBrowseDomain(m, &dDNSRegDomain, mDNStrue);
- }
- }
-
- // Add new browse domains to internal list
-
- if ( BrowseDomains )
- {
- SetSCPrefsBrowseDomains( m, BrowseDomains, mDNStrue );
- }
-
- // Remove old browse domains from internal list
-
- if ( dDNSBrowseDomains )
- {
- SetSCPrefsBrowseDomains( m, dDNSBrowseDomains, mDNSfalse );
- mDNS_FreeDNameList( dDNSBrowseDomains );
- }
-
- // Replace the old browse domains array with the new array
-
- dDNSBrowseDomains = BrowseDomains;
-
-
- if (!SameDomainName(&fqdn, &dDNSHostname))
- {
- if (dDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &dDNSHostname);
- AssignDomainName(&dDNSHostname, &fqdn);
- if (dDNSHostname.c[0])
- {
- dDNSPlatformSetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
- mDNS_AddDynDNSHostName(m, &dDNSHostname, SCPrefsdDNSCallback, mDNSNULL);
- dDNSPlatformSetNameStatus(&dDNSHostname, 1);
- }
- }
-
- // get DNS settings
- // YO SCDynamicStoreRef store = SCDynamicStoreCreate(mDNSNULL, CFSTR("mDNSResponder:dDNSConfigChanged"), mDNSNULL, mDNSNULL);
- // YO if (!store) return;
-
- // YO key = SCDynamicStoreKeyCreateNetworkGlobalEntity(mDNSNULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
- // YO if (!key) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
- // YO dict = SCDynamicStoreCopyValue(store, key);
- // YO CFRelease(key);
-
- // handle any changes to search domains and DNS server addresses
-
- if ( dDNSPlatformRegisterSplitDNS(m) != mStatus_NoError)
- if (dict) RegisterNameServers( m ); // fall back to non-split DNS aware configuration on failure
-
- if ( dDNSRegisterSearchDomains == mDNStrue )
- dDNS_RegisterSearchDomains( m ); // note that we register name servers *before* search domains
-
- // if (dict) CFRelease(dict);
-
- // get IPv4 settings
- // YO key = SCDynamicStoreKeyCreateNetworkGlobalEntity(mDNSNULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
- // YO if (!key) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; }
- // YO dict = SCDynamicStoreCopyValue(store, key);
- // YO CFRelease(key);
- // YO CFRelease(store);
- // YO if (!dict)
- // YO { mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL); return; } // lost v4
-
- // handle router changes
- // YO mDNSAddr r;
- // YO char buf[256];
- // YO r.type = mDNSAddrType_IPv4;
- // YO r.ip.v4.NotAnInteger = 0;
- // YO CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
- // YO if (router)
- // YO {
- // YO if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
- // YO LogMsg("Could not convert router to CString");
- // YO else inet_aton(buf, (struct in_addr *)&r.ip.v4);
- // YO }
-
- // handle router and primary interface changes
-
- ip.type = r.type = mDNSAddrType_IPv4;
- ip.ip.v4.NotAnInteger = r.ip.v4.NotAnInteger = 0;
-
- if ( dDNSPlatformGetPrimaryInterface( m, &ip, &r ) == mStatus_NoError )
- {
- // For now, we're going to pass NULL for the IPv6 parameter so that the Windows code compiles. What needs
- // to happen is that the implementation of dDNSPlatformGetPrimaryInterface() needs to call the
- // IPv6 aware "GetAdaptersAddresses" rather than GetAdaptersInfo().
- mDNS_SetPrimaryInterfaceInfo(m, &ip, NULL, r.ip.v4.NotAnInteger ? &r : mDNSNULL);
- }
-
- return mStatus_NoError;
-}
-
-
-// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
-// 1) query for b._dns-sd._udp.local on LocalOnly interface
-// (.local manually generated via explicit callback)
-// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
-// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
-// 4) result above should generate a callback from question in (1). result added to global list
-// 5) global list delivered to client via GetSearchDomainList()
-// 6) client calls to enumerate domains now go over LocalOnly interface
-// (!!!KRS may add outgoing interface in addition)
-
-mStatus dDNS_InitDNSConfig(mDNS *const m)
- {
- mStatus err;
- static AuthRecord LocalRegPTR;
-
- // start query for domains to be used in default (empty string domain) browses
- err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundDefBrowseDomain, NULL);
-
- // provide .local automatically
- SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
-
- // <rdar://problem/4055653> dns-sd -E does not return "local."
- // register registration domain "local"
- mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, NULL, NULL);
- MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]);
- AppendDNSNameString (LocalRegPTR.resrec.name, "local");
- AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain);
- err = mDNS_Register(m, &LocalRegPTR);
- if (err)
- {
- LogMsg("ERROR: dDNS_InitDNSConfig - mDNS_Register returned error %d", err);
- }
-
- return mStatus_NoError;
- }
-
-void
-dDNS_FreeIPAddrList(IPAddrListElem * list)
-{
- IPAddrListElem * fptr;
-
- while (list)
- {
- fptr = list;
- list = list->next;
- mDNSPlatformMemFree(fptr);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-*/
-
-
-#ifndef __dDNS_h
-#define __dDNS_h
-
-#include "mDNSEmbeddedAPI.h"
-#include "dns_sd.h"
-
-#if 0
-#pragma mark - DynDNS structures
-#endif
-
-#if WIN32
-// named type definition in parentheses \r
-# pragma warning( disable: 4115 ) \r
-#endif\r
-
-typedef struct IPAddrListElem
- {
- mDNSAddr addr;
- struct IPAddrListElem *next;
- } IPAddrListElem;
-
-extern void dDNS_FreeIPAddrList( IPAddrListElem * list );
-
-
-// ***************************************************************************
-#if 0
-#pragma mark - Main Client Functions
-#endif
-
-extern mStatus dDNS_Setup( mDNS *const m );
-extern mStatus dDNS_InitDNSConfig( mDNS *const m );
-extern mStatus dDNS_SetupAddr( mDNSAddr *ip, const struct sockaddr * const sa );
-
-
-// ***************************************************************************
-#if 0
-#pragma mark - PlatformSupport interface
-#endif
-
-// This section defines the interface to the DynDNS Platform Support layer.
-
-extern void dDNSPlatformGetConfig(domainname *const fqdn, domainname *const regDomain, DNameListElem ** browseDomains);
-extern void dDNSPlatformSetNameStatus(domainname *const dname, mStatus status);
-extern void dDNSPlatformSetSecretForDomain( mDNS *m, const domainname *domain );
-extern DNameListElem * dDNSPlatformGetSearchDomainList( void );
-extern DNameListElem * dDNSPlatformGetReverseMapSearchDomainList( void );
-extern IPAddrListElem * dDNSPlatformGetDNSServers( void );
-extern DNameListElem * dDNSPlatformGetDomainName( void );
-extern mStatus dDNSPlatformRegisterSplitDNS( mDNS *m );
-extern mStatus dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router );
-extern void dDNSPlatformDefaultBrowseDomainChanged( const domainname *d, mDNSBool add );
-extern void dDNSPlatformDefaultRegDomainChanged(const domainname *d, mDNSBool add);
-
-#endif
-
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSWin32.c,v $
-Revision 1.105 2005/11/27 20:21:16 herscher
-<rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
-
-Revision 1.104 2005/10/19 19:42:59 herscher
-<rdar://problem/4295946> Use the registry to determine the domain name, rather than using GetNetworkParams(). GetNetworkParams() does not reliably return domain information for the current network configuration.
-
-Revision 1.103 2005/10/18 06:13:20 herscher
-<rdar://problem/4192119> Prepend "$" to key name to ensure that secure updates work if the domain name and key name are the same
-
-Revision 1.102 2005/10/05 20:55:14 herscher
-<rdar://problem/4096464> Don't call SetLLRoute on loopback interface
-
-Revision 1.101 2005/10/05 18:05:28 herscher
-<rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
-
-Revision 1.100 2005/09/29 06:36:00 herscher
-Change check( err ) to check( !err ). This was a typo that was introduced in a previous checkin.
-
-Revision 1.99 2005/09/29 06:31:46 herscher
-<rdar://problem/4278934> Fall back to calling getifaddrs_ipv4 if getifaddrs_ipv6 fails
-
-Revision 1.98 2005/09/24 01:11:56 cheshire
-Add comment about GetWindowsVersionString
-
-Revision 1.97 2005/09/22 07:10:44 herscher
-<rdar://problem/4263713> Don't send domain enumeration query if domain is empty string or "."
-
-Revision 1.96 2005/09/22 07:06:06 herscher
-<rdar://problem/4252581> Don't loop uncontrollably upon detection of error in main event loop
-
-Revision 1.95 2005/09/11 22:51:40 herscher
-<rdar://problem/4249284> Obtain Hostname by using GetComputerNameEx, rather than gethostname.
-
-Revision 1.94 2005/09/11 21:43:15 herscher
-<rdar://problem/4245949> Don't create HINFO records on Windows
-
-Revision 1.93 2005/07/15 06:06:40 shersche
-<rdar://problem/4165134> Change all WinSock allocation loops to bail out after 100 tries to eliminate the possibility of any infinite loops
-
-Revision 1.92 2005/07/11 20:32:17 shersche
-<rdar://problem/4175515> Fix crash when logging into Cisco VPN
-
-Revision 1.91 2005/04/25 21:34:28 shersche
-<rdar://problem/4096465> Wide-Area services don't disappear when interface goes away
-
-Revision 1.90 2005/04/25 21:18:08 shersche
-<rdar://problem/4097314> mDNSResponder crash when interface goes away. This error seems to be caused by the Windows platform code not returning mStatus_TransientErr when there is a problem with a udp unicast send.
-
-Revision 1.89 2005/04/22 07:32:24 shersche
-<rdar://problem/4092108> PPP connection disables Bonjour .local lookups
-<rdar://problem/4093944> mDNSResponder ignores Point-to-Point interfaces
-
-Revision 1.88 2005/04/05 03:53:03 shersche
-<rdar://problem/4066485> Registering with shared secret key doesn't work.
-
-Revision 1.87 2005/04/03 08:03:12 shersche
-<rdar://problem/4076478> mDNSResponder won't start on Windows 2000.
-
-Revision 1.86 2005/03/30 07:37:14 shersche
-Use prefix to compute IPv4 subnet mask, falling back to calling AddressToIndexAndMask only if prefix is zero.
-
-Revision 1.85 2005/03/30 07:34:52 shersche
-<rdar://problem/4045657> Interface index being returned is 512
-
-Revision 1.84 2005/03/29 19:19:47 shersche
-<rdar://problem/4055599> Windows is not accepting unicast responses. This bug was a result of an error in obtaining the subnet mask for IPv4 interfaces.
-
-Revision 1.83 2005/03/07 18:27:42 shersche
-<rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
-
-Revision 1.82 2005/03/06 05:20:24 shersche
-<rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
-
-Revision 1.81 2005/03/04 22:44:53 shersche
-<rdar://problem/4022802> mDNSResponder did not notice changes to DNS server config
-
-Revision 1.80 2005/03/03 21:07:38 shersche
-<rdar://problem/4034460> mDNSResponder doesn't handle multiple browse domains
-
-Revision 1.79 2005/03/03 02:29:00 shersche
-Use the RegNames.h header file for registry key names
-
-Revision 1.78 2005/03/02 04:04:17 shersche
-Support for multiple browse domains
-
-Revision 1.77 2005/02/25 20:02:18 shersche
-<rdar://problem/4022802> Call ProcessingThreadDynDNSConfigChanged() when interface list changes
-
-Revision 1.76 2005/02/23 02:59:20 shersche
-<rdar://problem/4013482> Check to see if locks have been initialized before using them.
-
-Revision 1.75 2005/02/16 02:36:25 shersche
-<rdar://problem/3830846> Use IPv6 if interface has no routable IPv4 address
-
-Revision 1.74 2005/02/08 06:06:16 shersche
-<rdar://problem/3986597> Implement mDNSPlatformTCPConnect, mDNSPlatformTCPCloseConnection, mDNSPlatformTCPRead, mDNSPlatformTCPWrite
-
-Revision 1.73 2005/02/01 19:35:43 ksekar
-Removed obsolete arguments from mDNS_SetSecretForZone
-
-Revision 1.72 2005/02/01 01:38:53 shersche
-Handle null DynDNS configuration more gracefully
-
-Revision 1.71 2005/01/27 22:57:57 cheshire
-Fix compile errors on gcc4
-
-Revision 1.70 2005/01/25 08:12:52 shersche
-<rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
-Bug #: 3947417
-
-Revision 1.69 2005/01/11 04:39:48 shersche
-Workaround for GetAdaptersAddresses() bug in iphlpapi.dll
-
-Revision 1.68 2005/01/11 02:04:48 shersche
-Gracefully handle when IPv6 is not installed on a user's machine
-
-Revision 1.67 2004/12/18 00:51:52 cheshire
-Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
-
-Revision 1.66 2004/12/17 23:37:49 cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.65 2004/12/15 07:34:45 shersche
-Add platform support for IPv4 and IPv6 unicast sockets
-
-Revision 1.64 2004/12/15 06:06:15 shersche
-Fix problem in obtaining IPv6 subnet mask
-
-Revision 1.63 2004/11/23 03:39:47 cheshire
-Let interface name/index mapping capability live directly in JNISupport.c,
-instead of having to call through to the daemon via IPC to get this information.
-
-Revision 1.62 2004/11/12 03:16:41 rpantos
-rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName
-
-Revision 1.61 2004/11/05 22:54:38 shersche
-Change registry key flags from KEY_ALL_ACCESS to KEY_READ to support mDNSResponder running with limited access rights
-Submitted by: Pavel Repin <prepin@gmail.com>
-
-Revision 1.60 2004/11/05 22:41:56 shersche
-Determine subnet mask when populating network interface data structures
-Submitted by: Pavel Repin <prepin@gmail.com>
-Reviewed by:
-
-Revision 1.59 2004/10/28 03:24:42 cheshire
-Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353
-
-Revision 1.58 2004/10/16 00:17:01 cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
+Revision 1.128 2007/09/12 19:23:17 cheshire
+Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
-Revision 1.57 2004/10/11 21:53:15 shersche
-<rdar://problem/3832450> Change GetWindowsVersionString link scoping from static to non-static so that it can be accessed from other compilation units. The information returned in this function will be used to determine what service dependencies to use when calling CreateService().
-Bug #: 3832450
+Revision 1.127 2007/07/20 00:54:22 cheshire
+<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Revision 1.56 2004/09/26 23:20:36 ksekar
-<rdar://problem/3813108> Allow default registrations in multiple wide-area domains
+Revision 1.126 2007/07/11 02:56:20 cheshire
+<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
+Remove unused mDNSPlatformDefaultRegDomainChanged
-Revision 1.55 2004/09/21 21:02:57 cheshire
-Set up ifname before calling mDNS_RegisterInterface()
+Revision 1.125 2007/06/20 01:10:13 cheshire
+<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-Revision 1.54 2004/09/17 01:08:57 cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
- The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
- declared in that file are ONLY appropriate to single-address-space embedded applications.
- For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
+Revision 1.124 2007/04/26 00:35:16 cheshire
+<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
+Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
+inside the firewall may give answers where a public one gives none, and vice versa.)
-Revision 1.53 2004/09/17 00:19:11 cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
+Revision 1.123 2007/04/18 21:00:40 cheshire
+Use mDNS_AddSearchDomain_CString() instead of MakeDomainNameFromDNSNameString ... mDNS_AddSearchDomain
-Revision 1.52 2004/09/16 00:24:50 cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
+Revision 1.122 2007/04/17 19:21:29 cheshire
+<rdar://problem/5140339> Domain discovery not working over VPN
-Revision 1.51 2004/09/14 23:42:37 cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
+Revision 1.121 2007/04/05 20:40:37 cheshire
+Remove unused mDNSPlatformTCPGetFlags()
-Revision 1.50 2004/08/25 23:36:56 shersche
-<rdar://problem/3658379> Remove code that retrieves TTL from received packets
-Bug #: 3658379
+Revision 1.120 2007/03/28 20:59:27 cheshire
+<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-Revision 1.49 2004/08/25 16:43:29 ksekar
-Fix Windows build - change mDNS_SetFQDNs to mDNS_SetFQDN, remove unicast
-hostname parameter.
+Revision 1.119 2007/03/28 15:56:38 cheshire
+<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-Revision 1.48 2004/08/14 03:22:43 cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
+Revision 1.118 2007/03/22 18:31:49 cheshire
+Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-Revision 1.47 2004/08/06 17:33:02 shersche
-<rdar://problem/3753797> Put correct length of string in first byte of nicelabel
-Bug #: 3753797
+Revision 1.117 2007/03/21 00:30:07 cheshire
+<rdar://problem/4789455> Multiple errors in DNameList-related code
-Revision 1.46 2004/08/05 05:43:01 shersche
-<rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
-Bug #: 3751566
+Revision 1.116 2007/03/20 17:07:16 cheshire
+Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-Revision 1.45 2004/07/26 22:49:31 ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
+Revision 1.115 2007/02/08 21:12:28 cheshire
+<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-Revision 1.44 2004/07/26 05:42:50 shersche
-use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
+Revision 1.114 2007/01/05 08:31:01 cheshire
+Trim excessive "$Log" checkin history from before 2006
+(checkin history still available via "cvs log ..." of course)
-Revision 1.43 2004/07/13 21:24:25 rpantos
-Fix for <rdar://problem/3701120>.
+Revision 1.113 2007/01/04 23:12:20 cheshire
+Remove unused mDNSPlatformDefaultBrowseDomainChanged
-Revision 1.42 2004/06/24 15:23:24 shersche
-Add InterfaceListChanged callback. This callback is used in Service.c to add link local routes to the routing table
-Submitted by: herscher
+Revision 1.112 2006/12/22 20:59:51 cheshire
+<rdar://problem/4742742> Read *all* DNS keys from keychain,
+ not just key for the system-wide default registration domain
-Revision 1.41 2004/06/18 05:22:16 rpantos
-Integrate Scott's changes
+Revision 1.111 2006/12/19 22:43:56 cheshire
+Fix compiler warnings
-Revision 1.40 2004/05/26 09:06:07 bradley
-Retry while building the interface list if it returns an error since the two-step process required to
-get the interface list could allow a subsequent interface change to come in that window and change the
-needed size after getting the size, but before getting the list, causing it to return an error.
-Fixed structure name typo in search domain list stuff. Fixed spelling error in global for GAA.
+Revision 1.110 2006/09/27 00:47:40 herscher
+Fix compile error caused by changes to the tcp callback api.
-Revision 1.39 2004/05/18 23:51:27 cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+Revision 1.109 2006/08/14 23:25:21 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-Revision 1.38 2004/05/13 04:57:48 ksekar
-Removed unnecessary FreeSearchList function
+Revision 1.108 2006/07/06 00:06:21 cheshire
+<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Revision 1.37 2004/05/13 04:54:20 ksekar
-Unified list copy/free code. Added symetric list for
+Revision 1.107 2006/03/19 02:00:13 cheshire
+<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-Revision 1.36 2004/05/12 22:03:09 ksekar
-Made GetSearchDomainList a true platform-layer call (declaration moved
-from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local"
-only on non-OSX platforms. Changed call to return a copy of the list
-to avoid shared memory issues. Added a routine to free the list.
-
-Revision 1.35 2004/04/21 02:49:12 cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
-
-Revision 1.34 2004/04/15 01:00:05 bradley
-Removed support for automatically querying for A/AAAA records when resolving names. Platforms
-without .local name resolving support will need to manually query for A/AAAA records as needed.
-
-Revision 1.33 2004/04/14 23:09:29 ksekar
-Support for TSIG signed dynamic updates.
-
-Revision 1.32 2004/04/09 17:40:26 cheshire
-Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field
-
-Revision 1.31 2004/04/09 00:40:46 bradley
-Re-enable IPv6 support, AAAA records over IPv4, and IPv4 routable IPv6 exclusion support.
-
-Revision 1.30 2004/04/09 00:33:58 bradley
-Turn on Multicast flag for interfaces to tell mDNSCore that the interfaces are multicast capable.
-
-Revision 1.29 2004/03/15 02:07:46 bradley
-Changed interface index handling to use the upper 24 bits for IPv4 and the lower 8 bits for IPv6 to
-handle some IPv4 interface indexes that are greater than 16-bit. This is not perfect because Windows
-does not provide a consistent index for IPv4 and IPv6, but it seems to handle the known cases.
-
-Revision 1.28 2004/03/07 00:26:39 bradley
-Allow non-NULL PlatformSupport ptr when initializing so non-Apple clients can provide their own storage.
-Added count assert when building the wait list to catch underruns/overruns if the code is changed.
-
-Revision 1.27 2004/01/30 02:44:32 bradley
-Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
-InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
-are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
-(it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
-software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
-reporting HINFO records with the Windows and mDNSResponder version information.
-
-Revision 1.26 2004/01/24 04:59:16 cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
-
-Revision 1.25 2003/11/14 20:59:09 cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.24 2003/10/24 23:23:02 bradley
-Removed legacy port 53 support as it is no longer needed.
-
-Revision 1.23 2003/10/14 03:26:12 bradley
-Clear interface list buffer to workaround Windows CE bug where interfaces are not reported correctly.
-
-Revision 1.22 2003/08/20 06:21:25 bradley
-Updated to latest internal version of the mDNSWindows platform layer: Added support
-for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
-restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
-the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
-enable ThreadID improvement to wakeup notification; Define platform support structure locally to
-allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
-structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
-platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
-Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
-
-Revision 1.21 2003/08/18 23:09:57 cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
-
-Revision 1.20 2003/08/12 19:56:27 cheshire
-Update to APSL 2.0
-
-Revision 1.19 2003/08/05 23:58:18 cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
-
-Revision 1.18 2003/07/23 21:16:30 cheshire
-Removed a couple of debugfs
-
-Revision 1.17 2003/07/23 02:23:01 cheshire
-Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
-"ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
-
-Revision 1.16 2003/07/19 03:15:16 cheshire
-Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h,
-and add the obvious trivial implementations to each platform support layer
-
-Revision 1.15 2003/07/02 21:20:04 cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.14 2003/05/26 03:21:30 cheshire
-Tidy up address structure naming:
-mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.13 2003/05/26 03:01:28 cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.12 2003/05/06 21:06:05 cheshire
-<rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
-
-Revision 1.11 2003/05/06 00:00:51 cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.10 2003/04/29 00:06:09 cheshire
-<rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
-
-Revision 1.9 2003/04/26 02:40:01 cheshire
-Add void LogMsg( const char *format, ... )
-
-Revision 1.8 2003/03/22 02:57:44 cheshire
-Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.7 2003/03/15 04:40:38 cheshire
-Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID"
-
-Revision 1.6 2003/02/21 01:54:10 cheshire
-<rdar://problem/3099194> mDNSResponder needs performance improvements
-Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt")
-
-Revision 1.5 2003/02/20 00:59:03 cheshire
-Brought Windows code up to date so it complies with
-Josh Graessley's interface changes for IPv6 support.
-(Actual support for IPv6 on Windows will come later.)
-
-Revision 1.4 2002/09/21 20:44:54 zarzycki
-Added APSL info
-
-Revision 1.3 2002/09/20 05:50:45 bradley
-Multicast DNS platform plugin for Win32
+Revision 1.106 2006/02/26 19:31:05 herscher
+<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency. The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it. 2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
To Do:
- Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
- Get DNS server address(es) from Windows and provide them to the uDNS layer.
- Implement TCP support for truncated packets (only stubs now).
+
*/
#include <stdarg.h>
#define kIPv6IfIndexBase (10000000L)
+#define kRetryVPCRate (-100000000)
+#define kRetryVPCMax (10)
+
#if 0
#pragma mark == Prototypes ==
mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS );
mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS );
+mDNSlocal mStatus SetupRetryVPCCheck( mDNS * const inMDNS );
+mDNSlocal mStatus TearDownRetryVPCCheck( mDNS * const inMDNS );
mDNSlocal mStatus SetupThread( mDNS * const inMDNS );
mDNSlocal mStatus TearDownThread( const mDNS * const inMDNS );
mDNSlocal void ProcessingThreadComputerDescriptionChanged( mDNS * inMDNS );
mDNSlocal void ProcessingThreadTCPIPConfigChanged( mDNS * inMDNS );
mDNSlocal void ProcessingThreadDynDNSConfigChanged( mDNS * inMDNS );
+mDNSlocal void ProcessingThreadRetryVPCCheck( mDNS * inMDNS );
// Platform Accessors
mDNSAddr ip;
};
-typedef struct mDNSTCPConnectionData mDNSTCPConnectionData;
-struct mDNSTCPConnectionData
+struct TCPSocket_struct
{
- SocketRef sock;
- BOOL connected;
- TCPConnectionCallback callback;
- void * context;
- HANDLE pendingEvent;
- mDNSTCPConnectionData * next;
+ SocketRef fd;
+ TCPSocketFlags flags;
+ BOOL connected;
+ TCPConnectionCallback callback;
+ void * context;
+ HANDLE pendingEvent;
+ TCPSocket * next;
};
mDNSlocal OSStatus WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
mDNSlocal OSStatus MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input );
mDNSlocal OSStatus MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input );
-mDNSlocal void FreeTCPConnectionData( mDNSTCPConnectionData * data );
+mDNSlocal void FreeTCPSocket( TCPSocket *sock );
+mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
#ifdef __cplusplus
}
// Globals
//===========================================================================================================================
-mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
-mDNSs32 mDNSPlatformOneSecond = 0;
-mDNSlocal mDNSTCPConnectionData * gTCPConnectionList = NULL;
-mDNSlocal int gTCPConnections = 0;
-mDNSlocal BOOL gWaitListChanged = FALSE;
+mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
+mDNSs32 mDNSPlatformOneSecond = 0;
+mDNSlocal TCPSocket * gTCPConnectionList = NULL;
+mDNSlocal int gTCPConnections = 0;
+mDNSlocal BOOL gWaitListChanged = FALSE;
#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
// mDNSPlatformInit
//===========================================================================================================================
-mStatus mDNSPlatformInit( mDNS * const inMDNS )
+mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS )
{
mStatus err;
WSADATA wsaData;
inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
#endif
+
+ // Bookkeeping
+
+ inMDNS->p->vpcCheckCount = 0;
+ inMDNS->p->vpcCheckEvent = NULL;
+ inMDNS->p->timersCount = 0;
// Set up the IPv4 unicast socket
{
DWORD size;
- // If we are running inside VPC, then we won't use WSARecvMsg because it will give us bogus information due to
- // a bug in VPC itself.
-
- err = IsVPCRunning();
-
- if ( !err )
- {
- err = WSAIoctl( inMDNS->p->unicastSock4, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID,
+ err = WSAIoctl( inMDNS->p->unicastSock4, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID,
sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4RecvMsgPtr, sizeof( inMDNS->p->unicastSock4RecvMsgPtr ), &size, NULL, NULL );
- }
if ( err )
{
// mDNSPlatformClose
//===========================================================================================================================
-void mDNSPlatformClose( mDNS * const inMDNS )
+mDNSexport void mDNSPlatformClose( mDNS * const inMDNS )
{
mStatus err;
err = TearDownInterfaceList( inMDNS );
check_noerr( err );
check( !inMDNS->p->inactiveInterfaceList );
+
+ err = TearDownRetryVPCCheck( inMDNS );
+ check_noerr( err );
err = TearDownSynchronizationObjects( inMDNS );
check_noerr( err );
// mDNSPlatformSendUDP
//===========================================================================================================================
-mStatus
+mDNSexport mStatus
mDNSPlatformSendUDP(
const mDNS * const inMDNS,
const void * const inMsg,
// mDNSPlatformLock
//===========================================================================================================================
-void mDNSPlatformLock( const mDNS * const inMDNS )
+mDNSexport void mDNSPlatformLock( const mDNS * const inMDNS )
{
check( inMDNS );
// mDNSPlatformUnlock
//===========================================================================================================================
-void mDNSPlatformUnlock( const mDNS * const inMDNS )
+mDNSexport void mDNSPlatformUnlock( const mDNS * const inMDNS )
{
check( inMDNS );
check( inMDNS->p );
// mDNSPlatformStrCopy
//===========================================================================================================================
-void mDNSPlatformStrCopy( const void *inSrc, void *inDst )
+mDNSexport void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
{
check( inSrc );
check( inDst );
// mDNSPlatformStrLen
//===========================================================================================================================
-mDNSu32 mDNSPlatformStrLen( const void *inSrc )
+mDNSexport mDNSu32 mDNSPlatformStrLen( const void *inSrc )
{
check( inSrc );
// mDNSPlatformMemCopy
//===========================================================================================================================
-void mDNSPlatformMemCopy( const void *inSrc, void *inDst, mDNSu32 inSize )
+mDNSexport void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
{
check( inSrc );
check( inDst );
// mDNSPlatformMemSame
//===========================================================================================================================
-mDNSBool mDNSPlatformMemSame( const void *inSrc, const void *inDst, mDNSu32 inSize )
+mDNSexport mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
{
check( inSrc );
check( inDst );
// mDNSPlatformMemZero
//===========================================================================================================================
-void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
+mDNSexport void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
{
check( inDst );
// mDNSPlatformRawTime
//===========================================================================================================================
-mDNSs32 mDNSPlatformRawTime( void )
+mDNSexport mDNSs32 mDNSPlatformRawTime( void )
{
return( (mDNSs32) GetTickCount() );
}
// mDNSPlatformInterfaceNameToID
//===========================================================================================================================
-mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
+mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
{
mStatus err;
mDNSInterfaceData * ifd;
// mDNSPlatformInterfaceIDToInfo
//===========================================================================================================================
-mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
+mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
{
mStatus err;
mDNSInterfaceData * ifd;
// mDNSPlatformInterfaceIDfromInterfaceIndex
//===========================================================================================================================
-mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS * const inMDNS, mDNSu32 inIndex )
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
{
mDNSInterfaceID id;
// mDNSPlatformInterfaceIndexfromInterfaceID
//===========================================================================================================================
-mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mDNSInterfaceID inID )
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID )
{
mDNSu32 index;
return( index );
}
+//===========================================================================================================================
+// mDNSPlatformTCPSocket
+//===========================================================================================================================
+
+TCPSocket *
+mDNSPlatformTCPSocket
+ (
+ mDNS * const m,
+ TCPSocketFlags flags,
+ mDNSIPPort * port
+ )
+{
+ TCPSocket * sock = NULL;
+ u_long on = 1; // "on" for setsockopt
+ struct sockaddr_in saddr;
+ int len;
+ mStatus err = mStatus_NoError;
+
+ DEBUG_UNUSED( m );
+
+ require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
+
+ // Setup connection data object
+
+ sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
+ require_action( sock, exit, err = mStatus_NoMemoryErr );
+ memset( sock, 0, sizeof( TCPSocket ) );
+
+ sock->fd = INVALID_SOCKET;
+ sock->flags = flags;
+
+ bzero(&saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = htonl( INADDR_ANY );
+ saddr.sin_port = port->NotAnInteger;
+
+ // Create the socket
+
+ sock->fd = socket(AF_INET, SOCK_STREAM, 0);
+ err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
+ require_noerr( err, exit );
+
+ // Set it to be non-blocking
+
+ err = ioctlsocket( sock->fd, FIONBIO, &on );
+ err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
+ require_noerr( err, exit );
+
+ // Get port number
+
+ memset( &saddr, 0, sizeof( saddr ) );
+ len = sizeof( saddr );
+
+ err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
+ err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
+ require_noerr( err, exit );
+
+ port->NotAnInteger = saddr.sin_port;
+
+exit:
+
+ if ( err && sock )
+ {
+ FreeTCPSocket( sock );
+ sock = mDNSNULL;
+ }
+
+ return sock;
+}
+
//===========================================================================================================================
// mDNSPlatformTCPConnect
//===========================================================================================================================
mStatus
- mDNSPlatformTCPConnect(
- const mDNSAddr * inDstIP,
- mDNSOpaque16 inDstPort,
- mDNSInterfaceID inInterfaceID,
- TCPConnectionCallback inCallback,
- void * inContext,
- int * outSock )
+mDNSPlatformTCPConnect
+ (
+ TCPSocket * sock,
+ const mDNSAddr * inDstIP,
+ mDNSOpaque16 inDstPort,
+ mDNSInterfaceID inInterfaceID,
+ TCPConnectionCallback inCallback,
+ void * inContext
+ )
{
- u_long on = 1; // "on" for setsockopt
- struct sockaddr_in saddr;
- mDNSTCPConnectionData * tcd = NULL;
- mStatus err = mStatus_NoError;
+ struct sockaddr_in saddr;
+ mStatus err = mStatus_NoError;
DEBUG_UNUSED( inInterfaceID );
- *outSock = INVALID_SOCKET;
-
if ( inDstIP->type != mDNSAddrType_IPv4 )
{
LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
// Setup connection data object
- tcd = (mDNSTCPConnectionData*) malloc( sizeof( mDNSTCPConnectionData ) );
- require_action( tcd, exit, err = mStatus_NoMemoryErr );
- memset( tcd, 0, sizeof( mDNSTCPConnectionData ) );
-
- tcd->sock = INVALID_SOCKET;
- tcd->callback = inCallback;
- tcd->context = inContext;
+ sock->callback = inCallback;
+ sock->context = inContext;
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = inDstPort.NotAnInteger;
memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
- // Create the socket
-
- tcd->sock = socket(AF_INET, SOCK_STREAM, 0);
- err = translate_errno( tcd->sock != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- // Set it to be non-blocking
-
- err = ioctlsocket( tcd->sock, FIONBIO, &on );
- err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
// Try and do connect
- err = connect( tcd->sock, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
+ err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
- tcd->connected = !err ? TRUE : FALSE;
- tcd->pendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- err = translate_errno( tcd->pendingEvent, GetLastError(), mStatus_UnknownErr );
+ sock->connected = !err ? TRUE : FALSE;
+ sock->pendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ err = translate_errno( sock->pendingEvent, GetLastError(), mStatus_UnknownErr );
require_noerr( err, exit );
- err = WSAEventSelect( tcd->sock, tcd->pendingEvent, FD_CONNECT|FD_READ|FD_CLOSE );
+ err = WSAEventSelect( sock->fd, sock->pendingEvent, FD_CONNECT|FD_READ|FD_CLOSE );
require_noerr( err, exit );
// Bookkeeping
- tcd->next = gTCPConnectionList;
- gTCPConnectionList = tcd;
+ sock->next = gTCPConnectionList;
+ gTCPConnectionList = sock;
gTCPConnections++;
gWaitListChanged = TRUE;
- *outSock = (int) tcd->sock;
-
exit:
if ( !err )
{
- err = tcd->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
- }
- else if ( tcd )
- {
- FreeTCPConnectionData( tcd );
+ err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
}
return err;
}
+//===========================================================================================================================
+// mDNSPlatformTCPAccept
+//===========================================================================================================================
+
+mDNSexport
+mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd )
+ {
+ TCPSocket * sock = NULL;
+ mStatus err = mStatus_NoError;
+
+ require_action( !flags, exit, err = mStatus_UnsupportedErr );
+
+ sock = malloc( sizeof( TCPSocket ) );
+ require_action( sock, exit, err = mStatus_NoMemoryErr );
+
+ memset( sock, 0, sizeof( *sock ) );
+
+ sock->fd = fd;
+ sock->flags = flags;
+
+exit:
+
+ if ( err && sock )
+ {
+ free( sock );
+ sock = NULL;
+ }
+
+ return sock;
+ }
+
+
//===========================================================================================================================
// mDNSPlatformTCPCloseConnection
//===========================================================================================================================
-void mDNSPlatformTCPCloseConnection( int inSock )
+mDNSexport void mDNSPlatformTCPCloseConnection( TCPSocket *sock )
{
- mDNSTCPConnectionData * tcd = gTCPConnectionList;
- mDNSTCPConnectionData * last = NULL;
+ TCPSocket * inserted = gTCPConnectionList;
+ TCPSocket * last = NULL;
- while ( tcd )
+ while ( inserted )
{
- if ( tcd->sock == ( SOCKET ) inSock )
+ if ( inserted == sock )
{
if ( last == NULL )
{
- gTCPConnectionList = tcd->next;
+ gTCPConnectionList = inserted->next;
}
else
{
- last->next = tcd->next;
+ last->next = inserted->next;
}
- FreeTCPConnectionData( tcd );
-
gTCPConnections--;
gWaitListChanged = TRUE;
break;
}
- last = tcd;
- tcd = tcd->next;
+ last = inserted;
+ inserted = inserted->next;
}
+
+ FreeTCPSocket( sock );
}
//===========================================================================================================================
// mDNSPlatformReadTCP
//===========================================================================================================================
-int mDNSPlatformReadTCP( int inSock, void *inBuffer, int inBufferSize )
+mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
{
- int nread;
- OSStatus err;
+ int nread;
- nread = recv( inSock, inBuffer, inBufferSize, 0);
- err = translate_errno( ( nread >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
+ nread = recv( sock->fd, inBuffer, inBufferSize, 0);
if ( nread < 0 )
{
- nread = 0;
+ if ( WSAGetLastError() == WSAEWOULDBLOCK )
+ {
+ nread = 0;
+ }
+ else
+ {
+ nread = -1;
+ }
+ }
+ else if ( !nread )
+ {
+ *closed = mDNStrue;
}
-exit:
-
return nread;
}
// mDNSPlatformWriteTCP
//===========================================================================================================================
-int mDNSPlatformWriteTCP( int inSock, const char *inMsg, int inMsgSize )
+mDNSexport long mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
{
int nsent;
OSStatus err;
- nsent = send( inSock, inMsg, inMsgSize, 0 );
+ nsent = send( sock->fd, inMsg, inMsgSize, 0 );
err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
require_noerr( err, exit );
}
//===========================================================================================================================
-// dDNSPlatformGetConfig
+// mDNSPlatformTCPGetFD
+//===========================================================================================================================
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
+ {
+ return ( int ) sock->fd;
+ }
+
+//===========================================================================================================================
+// mDNSPlatformUDPSocket
+//===========================================================================================================================
+
+mDNSexport UDPSocket *mDNSPlatformUDPSocket
+ (
+ mDNS * const m,
+ mDNSIPPort port
+ )
+ {
+ DEBUG_UNUSED( m );
+ DEBUG_UNUSED( port );
+
+ return NULL;
+ }
+
+//===========================================================================================================================
+// mDNSPlatformUDPClose
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
+ {
+ DEBUG_UNUSED( sock );
+ }
+
+
+//===========================================================================================================================
+// mDNSPlatformTLSSetupCerts
+//===========================================================================================================================
+
+mDNSexport mStatus
+mDNSPlatformTLSSetupCerts(void)
+{
+ return mStatus_UnsupportedErr;
+}
+
+//===========================================================================================================================
+// mDNSPlatformTLSTearDownCerts
//===========================================================================================================================
+mDNSexport void
+mDNSPlatformTLSTearDownCerts(void)
+{
+}
+
+//===========================================================================================================================
+// mDNSPlatformSetDNSConfig
+//===========================================================================================================================
+
+mDNSlocal void SetDNSServers( mDNS *const m );
+mDNSlocal void SetSearchDomainList( void );
+
void
-dDNSPlatformGetConfig(domainname * const fqdn, domainname *const regDomain, DNameListElem ** browseDomains)
+mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **browseDomains)
{
LPSTR name = NULL;
char subKeyName[kRegistryMaxKeyLength + 1];
DWORD i;
OSStatus err;
+ if (setservers) SetDNSServers(m);
+ if (setsearch) SetSearchDomainList();
+
// Initialize
- fqdn->c[0] = regDomain->c[0] = '\0';
+ fqdn->c[0] = '\0';
*browseDomains = NULL;
err = RegQueryString( key, "", &name, &dwSize, &enabled );
if ( !err && ( name[0] != '\0' ) && enabled )
{
- if ( !MakeDomainNameFromDNSNameString( regDomain, name ) || !regDomain->c[0] )
+ *RegDomains = (DNameListElem*) malloc( sizeof( DNameListElem ) );
+ if (!*RegDomains) dlog( kDebugLevelError, "No memory");
+ else
{
- dlog( kDebugLevelError, "bad DDNS registration domain in registry: %s", name[0] ? name : "(unknown)");
+ (*RegDomains)->next = mDNSNULL;
+ if ( !MakeDomainNameFromDNSNameString( &(*RegDomains)->name, name ) || (*RegDomains)->name.c[0] )
+ {
+ dlog( kDebugLevelError, "bad DDNS registration domain in registry: %s", name[0] ? name : "(unknown)");
+ }
}
}
//===========================================================================================================================
-// dDNSPlatformSetNameStatus
+// mDNSPlatformDynDNSHostNameStatusChanged
//===========================================================================================================================
-void
-dDNSPlatformSetNameStatus(domainname *const dname, mStatus status)
+mDNSexport void
+mDNSPlatformDynDNSHostNameStatusChanged(domainname *const dname, mStatus status)
{
char uname[MAX_ESCAPED_DOMAIN_NAME];
LPCTSTR name;
//===========================================================================================================================
-// dDNSPlatformSetSecretForDomain
+// SetDomainSecrets
//===========================================================================================================================
-void
-dDNSPlatformSetSecretForDomain( mDNS *m, const domainname * inDomain )
+// This routine needs to be called whenever the system secrets database changes.
+// Right now I call it from ProcessingThreadDynDNSConfigChanged, which may or may not be sufficient.
+// Also, it needs to call mDNS_SetSecretForDomain() for *every* configured DNS domain/secret pair
+// in the database, not just inDomain (the inDomain parameter should be deleted).
+
+mDNSlocal void
+SetDomainSecrets( mDNS * const m, const domainname * inDomain )
{
PolyString domain;
PolyString key;
// And finally, tell the core about this secret
debugf("Setting shared secret for zone %s with key %##s", domain.m_utf8, key.m_dname.c);
- mDNS_SetSecretForZone( m, &domain.m_dname, &key.m_dname, secret.m_utf8 );
+ mDNS_SetSecretForDomain( m, &domain.m_dname, &key.m_dname, secret.m_utf8, mDNSfalse );
exit:
//===========================================================================================================================
-// dDNSPlatformGetSearchDomainList
+// SetSearchDomainList
//===========================================================================================================================
-DNameListElem*
-dDNSPlatformGetSearchDomainList( void )
+mDNSlocal void SetDomainFromDHCP( void );
+mDNSlocal void SetReverseMapSearchDomainList( void );
+
+mDNSlocal void
+SetSearchDomainList( void )
{
char * searchList = NULL;
DWORD searchListLen;
while ( tok )
{
if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
- {
- domainname domain;
-
- if ( MakeDomainNameFromDNSNameString( &domain, tok ) )
- {
- DNameListElem * last = current;
-
- current = (DNameListElem*) malloc( sizeof( DNameListElem ) );
- require_action( current, exit, err = mStatus_NoMemoryErr );
-
- AssignDomainName( ¤t->name, &domain );
- current->next = NULL;
-
- if ( !head )
- {
- head = current;
- }
-
- if ( last )
- {
- last->next = current;
- }
- }
- }
-
+ mDNS_AddSearchDomain_CString(tok);
tok = strtok( NULL, "," );
}
RegCloseKey( key );
}
- return head;
+ SetDomainFromDHCP();
+ SetReverseMapSearchDomainList();
}
//===========================================================================================================================
-// dDNSPlatformGetReverseMapSearchDomainList
+// SetReverseMapSearchDomainList
//===========================================================================================================================
-DNameListElem*
-dDNSPlatformGetReverseMapSearchDomainList( void )
+mDNSlocal void
+SetReverseMapSearchDomainList( void )
{
- DNameListElem * head = NULL;
- DNameListElem * current = NULL;
struct ifaddrs * ifa;
- mStatus err;
ifa = myGetIfAddrs( 1 );
while (ifa)
{
mDNSAddr addr;
- if (ifa->ifa_addr->sa_family == AF_INET && !dDNS_SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
+ if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
{
mDNSAddr netmask;
- domainname domain;
char buffer[256];
- if (!dDNS_SetupAddr(&netmask, ifa->ifa_netmask))
+ if (!SetupAddr(&netmask, ifa->ifa_netmask))
{
sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
addr.ip.v4.b[2] & netmask.ip.v4.b[2],
addr.ip.v4.b[1] & netmask.ip.v4.b[1],
addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
-
- if ( MakeDomainNameFromDNSNameString( &domain, buffer ) )
- {
- DNameListElem * last = current;
-
- current = (DNameListElem*) malloc( sizeof( DNameListElem ) );
- require_action( current, exit, err = mStatus_NoMemoryErr );
-
- AssignDomainName( ¤t->name, &domain );
- current->next = NULL;
-
- if ( !head )
- {
- head = current;
- }
-
- if ( last )
- {
- last->next = current;
- }
- }
+ mDNS_AddSearchDomain_CString(buffer);
}
}
}
exit:
-
- return head;
}
//===========================================================================================================================
-// dDNSPlatformGetDNSServers
+// SetDNSServers
//===========================================================================================================================
-IPAddrListElem*
-dDNSPlatformGetDNSServers( void )
+mDNSlocal void
+SetDNSServers( mDNS *const m )
{
PIP_PER_ADAPTER_INFO pAdapterInfo = NULL;
FIXED_INFO * fixedInfo = NULL;
ULONG bufLen = 0;
IP_ADDR_STRING * dnsServerList;
IP_ADDR_STRING * ipAddr;
- IPAddrListElem * head = NULL;
- IPAddrListElem * current = NULL;
DWORD index;
int i = 0;
mStatus err = kUnknownErr;
for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
{
- mDNSAddr addr;
- IPAddrListElem * last = current;
-
+ mDNSAddr addr;
err = StringToAddress( &addr, ipAddr->IpAddress.String );
-
- if ( err )
- {
- continue;
- }
-
- current = (IPAddrListElem*) malloc( sizeof( IPAddrListElem ) );
- require_action( current, exit, err = mStatus_NoMemoryErr );
-
- memcpy( ¤t->addr, &addr, sizeof( mDNSAddr ) );
- current->next = NULL;
-
- if ( !head )
- {
- head = current;
- }
-
- if ( last )
- {
- last->next = current;
- }
+ if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, addr, UnicastDNSPort);
}
exit:
{
GlobalFree( fixedInfo );
}
-
- return head;
}
//===========================================================================================================================
-// dDNSPlatformGetDomainName
+// SetDomainFromDHCP
//===========================================================================================================================
-DNameListElem*
-dDNSPlatformGetDomainName( void )
+mDNSlocal void
+SetDomainFromDHCP( void )
{
DNameListElem * head = NULL;
int i = 0;
check_noerr( err );
}
- if ( domain && domain[0] && ( MakeDomainNameFromDNSNameString( &dname, domain ) || !dname.c[0] ) )
- {
- head = (DNameListElem*) malloc( sizeof( DNameListElem ) );
- require_action( head, exit, err = mStatus_NoMemoryErr );
-
- AssignDomainName( &head->name, &dname );
- head->next = NULL;
- }
+ if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain);
break;
}
{
RegCloseKey( key );
}
-
- return head;
-}
-
-
-//===========================================================================================================================
-// dDNSPlatformRegisterSplitDNS
-//===========================================================================================================================
-
-mStatus
-dDNSPlatformRegisterSplitDNS( mDNS * m )
-{
- DEBUG_UNUSED( m );
-
- return mStatus_UnsupportedErr;
}
//===========================================================================================================================
-// dDNSPlatformGetPrimaryInterface
+// mDNSPlatformGetPrimaryInterface
//===========================================================================================================================
-mStatus
-dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router )
+mDNSexport mStatus
+mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
{
IP_ADAPTER_INFO * pAdapterInfo;
IP_ADAPTER_INFO * pAdapter;
DEBUG_UNUSED( m );
+ *v6 = zeroAddr;
+
pAdapterInfo = NULL;
bufLen = 0;
found = FALSE;
pAdapter->IpAddressList.IpAddress.String[0] &&
pAdapter->GatewayList.IpAddress.String &&
pAdapter->GatewayList.IpAddress.String[0] &&
- ( StringToAddress( primary, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
+ ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
( !index || ( pAdapter->Index == index ) ) )
{
}
-//===========================================================================================================================
-// dDNSPlatformDefaultBrowseDomainChanged
-//===========================================================================================================================
-
-void
-dDNSPlatformDefaultBrowseDomainChanged( const domainname *d, mDNSBool add )
-{
- DEBUG_UNUSED( d );
- DEBUG_UNUSED( add );
-
- // This is a no-op on Windows
-}
-
-
-//===========================================================================================================================
-// dDNSPlatformDefaultRegDomainChanged
-//===========================================================================================================================
-
-void
-dDNSPlatformDefaultRegDomainChanged( const domainname * d, mDNSBool add )
-{
- DEBUG_UNUSED( d );
- DEBUG_UNUSED( add );
-
- // This is a no-op on Windows
-}
-
-
#if 0
#pragma mark -
#endif
//===========================================================================================================================
#if( MDNS_DEBUGMSGS )
-void debugf_( const char *inFormat, ... )
+mDNSexport void debugf_( const char *inFormat, ... )
{
char buffer[ 512 ];
va_list args;
//===========================================================================================================================
#if( MDNS_DEBUGMSGS > 1 )
-void verbosedebugf_( const char *inFormat, ... )
+mDNSexport void verbosedebugf_( const char *inFormat, ... )
{
char buffer[ 512 ];
va_list args;
//===========================================================================================================================
/*
-void LogMsg( const char *inFormat, ... )
+mDNSexport void LogMsg( const char *inFormat, ... )
{
char buffer[ 512 ];
va_list args;
#if( !TARGET_OS_WINDOWS_CE )
{
- DWORD size;
+ DWORD size;
// If we are running inside VPC, then we won't use WSARecvMsg because it will give us bogus information due to
// a bug in VPC itself.
- err = IsVPCRunning();
+ err = inMDNS->p->inVirtualPC;
if ( !err )
{
ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses;
- err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, 0 );
+ err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
require_noerr( err, exit );
ifd->hostRegistered = mDNStrue;
if( inIFD->hostRegistered )
{
inIFD->hostRegistered = mDNSfalse;
- mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo );
+ mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, mDNSfalse );
}
// Tear down the multicast socket.
{
// Join the all-DNS multicast group so we receive Multicast DNS packets
- mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+ mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
{
// Join the all-DNS multicast group so we receive Multicast DNS packets.
- mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroupv6 );
+ mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroup_v6.ip.v6 );
mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
check_translated_errno( err == 0, errno_compat(), kOptionErr );
return( mStatus_NoError );
}
+
+//===========================================================================================================================
+// SetupRetryVPCCheck
+//===========================================================================================================================
+
+mDNSlocal mStatus
+SetupRetryVPCCheck( mDNS * const inMDNS )
+{
+ LARGE_INTEGER liDueTime;
+ BOOL ok;
+ mStatus err;
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "setting up retry VirtualPC check\n" );
+
+ liDueTime.QuadPart = kRetryVPCRate;
+
+ // Create a waitable timer.
+
+ inMDNS->p->vpcCheckEvent = CreateWaitableTimer( NULL, TRUE, TEXT( "VPCCheckTimer" ) );
+ err = translate_errno( inMDNS->p->vpcCheckEvent, (mStatus) GetLastError(), kUnknownErr );
+ require_noerr( err, exit );
+
+ // Set a timer to wait for 10 seconds.
+
+ ok = SetWaitableTimer( inMDNS->p->vpcCheckEvent, &liDueTime, 0, NULL, NULL, 0 );
+ err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
+ require_noerr( err, exit );
+
+ inMDNS->p->timersCount++;
+
+exit:
+
+ return err;
+}
+
+
+//===========================================================================================================================
+// TearDownRetryVPCCheck
+//===========================================================================================================================
+
+mDNSlocal mStatus
+TearDownRetryVPCCheck( mDNS * const inMDNS )
+{
+ dlog( kDebugLevelTrace, DEBUG_NAME "tearing down retry VirtualPC check\n" );
+
+ if ( inMDNS->p->vpcCheckEvent )
+ {
+ CancelWaitableTimer( inMDNS->p->vpcCheckEvent );
+ CloseHandle( inMDNS->p->vpcCheckEvent );
+
+ inMDNS->p->vpcCheckEvent = NULL;
+ inMDNS->p->timersCount--;
+ }
+
+ return ( mStatus_NoError );
+}
+
+
#if 0
#pragma mark -
#endif
{
HANDLE signaledObject;
int n = 0;
- mDNSInterfaceData * ifd;
- mDNSTCPConnectionData * tcd;
+ mDNSInterfaceData * ifd;
+ TCPSocket * tcd;
signaledObject = waitList[ waitItemIndex ];
+ if ( m->p->vpcCheckEvent == signaledObject )
+ {
+ ProcessingThreadRetryVPCCheck( m );
+ ++n;
+
+ break;
+ }
#if ( MDNS_WINDOWS_ENABLE_IPV4 )
if ( m->p->unicastSock4ReadEvent == signaledObject )
{
connect = mDNStrue;
}
- tcd->callback( ( int ) tcd->sock, tcd->context, connect );
+ tcd->callback( tcd, tcd->context, connect, 0 );
++n;
BOOL wasSet;
inMDNS->p->threadID = GetCurrentThreadId();
-
+
+ err = IsVPCRunning( &inMDNS->p->inVirtualPC );
+
+ if ( err )
+ {
+ TearDownRetryVPCCheck( inMDNS );
+ SetupRetryVPCCheck( inMDNS );
+ }
+
err = SetupInterfaceList( inMDNS );
require_noerr( err, exit );
- err = dDNS_Setup( inMDNS );
+ err = uDNS_SetupDNSConfig( inMDNS );
require_noerr( err, exit );
- err = dDNS_InitDNSConfig( inMDNS );
- require_noerr( err, exit );
-
exit:
if( err )
{
TearDownInterfaceList( inMDNS );
+ TearDownRetryVPCCheck( inMDNS );
}
inMDNS->p->initStatus = err;
mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
{
- mStatus err;
- int waitListCount;
- HANDLE * waitList;
- HANDLE * waitItemPtr;
- mDNSInterfaceData * ifd;
- mDNSTCPConnectionData * tcd;
+ mStatus err;
+ int waitListCount;
+ HANDLE * waitList;
+ HANDLE * waitItemPtr;
+ mDNSInterfaceData * ifd;
+ TCPSocket * tcd;
dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list\n" );
check( inMDNS );
// Allocate an array to hold all the objects to wait on.
- waitListCount = kWaitListFixedItemCount + inMDNS->p->interfaceCount + gTCPConnections;
+ waitListCount = kWaitListFixedItemCount + inMDNS->p->timersCount + inMDNS->p->interfaceCount + gTCPConnections;
waitList = (HANDLE *) malloc( waitListCount * sizeof( *waitList ) );
require_action( waitList, exit, err = mStatus_NoMemoryErr );
waitItemPtr = waitList;
*waitItemPtr++ = inMDNS->p->descChangedEvent;
*waitItemPtr++ = inMDNS->p->tcpipChangedEvent;
*waitItemPtr++ = inMDNS->p->ddnsChangedEvent;
+
+ // Add timers
+
+ if ( inMDNS->p->vpcCheckEvent )
+ {
+ *waitItemPtr++ = inMDNS->p->vpcCheckEvent;
+ }
// Append all the dynamic wait items to the list.
#if ( MDNS_WINDOWS_ENABLE_IPV4 )
err = SetupInterfaceList( inMDNS );
check_noerr( err );
- err = dDNS_Setup( inMDNS );
+ err = uDNS_SetupDNSConfig( inMDNS );
check_noerr( err );
// so that LLQs are restarted against the up to date name servers
mDNSPlatformLock( inMDNS );
- err = dDNS_Setup( inMDNS );
+ err = uDNS_SetupDNSConfig( inMDNS );
check_noerr( err );
// so that LLQs are restarted against the up to date name servers
dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
check( inMDNS );
+ SetDomainSecrets( inMDNS );
+
mDNSPlatformLock( inMDNS );
- err = dDNS_Setup( inMDNS );
+ err = uDNS_SetupDNSConfig( inMDNS );
check_noerr( err );
// so that LLQs are restarted against the up to date name servers
}
+//===========================================================================================================================
+// ProcessingThreadRetryVPCCheck
+//===========================================================================================================================
+
+mDNSlocal void
+ProcessingThreadRetryVPCCheck( mDNS * inMDNS )
+{
+ mStatus err = mStatus_NoError;
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "in ProcessingThreadRetryVPCCheck\n" );
+
+ TearDownRetryVPCCheck( inMDNS );
+
+ if ( inMDNS->p->vpcCheckCount < kRetryVPCMax )
+ {
+ inMDNS->p->vpcCheckCount++;
+
+ err = IsVPCRunning( &inMDNS->p->inVirtualPC );
+ require_noerr( err, exit );
+
+ if ( inMDNS->p->inVirtualPC )
+ {
+ ProcessingThreadInterfaceListChanged( inMDNS );
+ }
+ }
+
+exit:
+
+ if ( err )
+ {
+ SetupRetryVPCCheck( inMDNS );
+ }
+
+ return;
+}
+
+
+
#if 0
#pragma mark -
#pragma mark == Utilities ==
// getifaddrs
//===========================================================================================================================
-int getifaddrs( struct ifaddrs **outAddrs )
+mDNSlocal int getifaddrs( struct ifaddrs **outAddrs )
{
int err;
// freeifaddrs
//===========================================================================================================================
-void freeifaddrs( struct ifaddrs *inIFAs )
+mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs )
{
struct ifaddrs * p;
struct ifaddrs * q;
// GetWindowsVersionString
//===========================================================================================================================
-OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
+mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
{
#if( !defined( VER_PLATFORM_WIN32_CE ) )
#define VER_PLATFORM_WIN32_CE 3
// RegQueryString
//===========================================================================================================================
-static mStatus
+mDNSlocal mStatus
RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
{
DWORD type;
// StringToAddress
//===========================================================================================================================
-static mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
+mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
{
struct sockaddr_in6 sa6;
struct sockaddr_in sa4;
if ( err == mStatus_NoError )
{
- err = dDNS_SetupAddr( ip, (struct sockaddr*) &sa6 );
+ err = SetupAddr( ip, (struct sockaddr*) &sa6 );
require_noerr( err, exit );
}
else
err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
require_noerr( err, exit );
- err = dDNS_SetupAddr( ip, (struct sockaddr*) &sa4 );
+ err = SetupAddr( ip, (struct sockaddr*) &sa4 );
require_noerr( err, exit );
}
// ConvertLsaStringToUTF8
//===========================================================================================================================
-static OSStatus
+mDNSlocal OSStatus
MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input )
{
size_t size;
//===========================================================================================================================
mDNSlocal void
-FreeTCPConnectionData( mDNSTCPConnectionData * data )
+FreeTCPSocket( TCPSocket *sock )
{
- check( data );
+ check( sock );
- if ( data->pendingEvent )
+ if ( sock->pendingEvent )
{
- CloseHandle( data->pendingEvent );
+ CloseHandle( sock->pendingEvent );
}
- if ( data->sock != INVALID_SOCKET )
+ if ( sock->fd != INVALID_SOCKET )
{
- closesocket( data->sock );
+ closesocket( sock->fd );
}
- free( data );
+ free( sock );
}
+
+//===========================================================================================================================
+// SetupAddr
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
+ {
+ if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
+
+ if (sa->sa_family == AF_INET)
+ {
+ struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
+ ip->type = mDNSAddrType_IPv4;
+ ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
+ return(mStatus_NoError);
+ }
+
+ if (sa->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
+ ip->type = mDNSAddrType_IPv6;
+ if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
+ ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
+ return(mStatus_NoError);
+ }
+
+ LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
+ return(mStatus_Invalid);
+ }
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mDNSWin32.h,v $
+Revision 1.26 2006/08/14 23:25:21 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.25 2006/07/06 00:05:44 cheshire
+"dDNS.h" renamed to "uDNS.h"
+
+Revision 1.24 2006/02/26 19:31:04 herscher
+<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency. The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it. 2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
+
Revision 1.23 2005/10/05 20:55:14 herscher
<rdar://problem/4096464> Don't call SetLLRoute on loopback interface
#endif
#include "mDNSEmbeddedAPI.h"
-#include "dDNS.h"
+#include "uDNS.h"
#ifdef __cplusplus
extern "C" {
HANDLE ddnsChangedEvent; // DynDNS config changed
HANDLE wakeupEvent;
HANDLE initEvent;
+ HANDLE vpcCheckEvent; // Timer handle to check if we're running in Virtual PC
+ int vpcCheckCount;
HKEY descKey;
HKEY tcpipKey;
HKEY ddnsKey;
mStatus initStatus;
+ mDNSBool inVirtualPC;
+ int timersCount;
mDNSBool registeredLoopback4;
SocketRef interfaceListChangedSocket;
int interfaceCount;
-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: mdnsNSP.c,v $
+Revision 1.20 2006/08/14 23:26:10 cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.19 2006/06/08 23:09:37 cheshire
+Updated comment: Correct IPv6LL reverse-mapping domains are '{8,9,A,B}.E.F.ip6.arpa.',
+not only '0.8.E.F.ip6.arpa.' (Actual code still needs to be fixed.)
+
Revision 1.18 2005/10/17 05:45:36 herscher
Fix typo in previous checkin
require_action( InHostsTable( translated ) == FALSE, exit, err = WSASERVICE_NOT_FOUND );
}
- // The name ends in .local ( and isn't in the hosts table ), .0.8.e.f.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
+ // The name ends in .local ( and isn't in the hosts table ), {8,9,A,B}.E.F.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed.
NSPLock();
+; -*- tab-width: 4 -*-
;
; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
;
-; @APPLE_LICENSE_HEADER_START@
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
;
-; This file contains Original Code and/or Modifications of Original Code
-; as defined in and that are subject to the Apple Public Source License
-; Version 2.0 (the 'License'). You may not use this file except in
-; compliance with the License. Please obtain a copy of the License at
-; http://www.opensource.apple.com/apsl/ and read it before using this
-; file.
+; http://www.apache.org/licenses/LICENSE-2.0
;
-; The Original Code and all software distributed under the License are
-; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
-; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
-; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
-; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
-; Please see the License for the specific language governing rights and
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
; limitations under the License.
-;
-; @APPLE_LICENSE_HEADER_END@
;
; Change History (most recent first):
;
; $Log: mdnsNSP.def,v $
+; Revision 1.4 2006/08/14 23:26:10 cheshire
+; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+;
; Revision 1.3 2005/01/28 23:48:46 shersche
; <rdar://problem/3942551> Export DllRegisterServer, DllUnregisterServer which can be called from the Installer or regsvr32
; Bug #: 3942551
BEGIN
BLOCK "040904b0"
BEGIN
- VALUE "CompanyName", "Apple Computer, Inc."
+ VALUE "CompanyName", MASTER_COMPANY_NAME
VALUE "FileDescription", "Bonjour Namespace Provider"
VALUE "FileVersion", MASTER_PROD_VERS_STR
VALUE "InternalName", "mdnsNSP.dll"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
<File\r
- RelativePath="..\DebugServices.c">\r
+ RelativePath="..\..\mDNSShared\DebugServices.c">\r
</File>\r
<File\r
RelativePath=".\mdnsNSP.c">\r
Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
<File\r
- RelativePath="..\CommonServices.h">\r
+ RelativePath="..\..\mDNSShared\CommonServices.h">\r
</File>\r
<File\r
- RelativePath="..\DebugServices.h">\r
+ RelativePath="..\..\mDNSShared\DebugServices.h">\r
</File>\r
<File\r
RelativePath="..\..\..\mDNSShared\dns_sd.h">\r