├── ios-ntp-app ├── ntp.hosts ├── ntpAppDelegate.h ├── ntpAppDelegate.m ├── main.m ├── ntpViewController.h └── ntpViewController.m ├── release └── .gitignore ├── rfc5905.pdf ├── .gitignore ├── Default-568h@2x.png ├── draft-ietf-ntp-bcp-02.pdf ├── ios-ntp-rez ├── en.lproj │ ├── InfoPlist.strings │ ├── Storyboard.storyboard │ └── ntpViewController.xib ├── ios-ntp-Info.plist └── ntp-app-Info.plist ├── ios-ntp-lib ├── ntp-log.h ├── ios-ntp.h ├── NSDate+NetworkClock.m ├── NSDate+NetworkClock.h ├── NetworkClock.h ├── NetAssociation.h ├── Notes ├── NetworkClock.m └── NetAssociation.m ├── Podfile.lock ├── ios-ntp.podspec ├── Podfile ├── ntp-test ├── Info.plist └── ntp_test.m ├── LICENSE ├── README.md └── ios-ntp.xcodeproj └── project.pbxproj /ios-ntp-app/ntp.hosts: -------------------------------------------------------------------------------- 1 | time.apple.com 2 | -------------------------------------------------------------------------------- /release/.gitignore: -------------------------------------------------------------------------------- 1 | ios-ntp.framework/ 2 | -------------------------------------------------------------------------------- /rfc5905.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbenet/ios-ntp/HEAD/rfc5905.pdf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata/ 3 | project.xcworkspace 4 | Pods/ 5 | -------------------------------------------------------------------------------- /Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbenet/ios-ntp/HEAD/Default-568h@2x.png -------------------------------------------------------------------------------- /draft-ietf-ntp-bcp-02.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbenet/ios-ntp/HEAD/draft-ietf-ntp-bcp-02.pdf -------------------------------------------------------------------------------- /ios-ntp-rez/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | NSHumanReadableCopyright = "© Ramsay Consulting, 2010-21"; 4 | -------------------------------------------------------------------------------- /ios-ntp-lib/ntp-log.h: -------------------------------------------------------------------------------- 1 | #define NTP_Logging(fmt, ...) 2 | 3 | #ifdef IOS_NTP_LOGGING 4 | #undef NTP_Logging 5 | #define NTP_Logging(fmt, ...) \ 6 | NSLog((@"%@|" fmt), [NSString stringWithFormat: @"%16s", \ 7 | [[[self class] description] UTF8String]], ##__VA_ARGS__) 8 | #endif 9 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CocoaAsyncSocket (7.6.3) 3 | 4 | DEPENDENCIES: 5 | - CocoaAsyncSocket 6 | 7 | SPEC REPOS: 8 | https://github.com/cocoapods/specs.git: 9 | - CocoaAsyncSocket 10 | 11 | SPEC CHECKSUMS: 12 | CocoaAsyncSocket: eafaa68a7e0ec99ead0a7b35015e0bf25d2c8987 13 | 14 | PODFILE CHECKSUM: 51c3d8203034073fe136a0b01ede64bee89e01a5 15 | 16 | COCOAPODS: 1.5.3 17 | -------------------------------------------------------------------------------- /ios-ntp.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'ios-ntp' 3 | s.version = '1.1.9' 4 | s.license = { :type => 'MIT', :file => 'LICENSE' } 5 | s.homepage = 'https://github.com/jbenet/ios-ntp' 6 | s.author = { 'Gavin Eadie' => 'https://github.com/gavineadie' } 7 | s.summary = 'SNTP implementation for iOS.' 8 | s.source = { :git => 'https://github.com/jbenet/ios-ntp.git', :tag => '1.1.9' } 9 | s.source_files = 'ios-ntp-lib/*.{h,m}' 10 | s.ios.deployment_target = '9.0' 11 | s.tvos.deployment_target = '9.0' 12 | s.dependency 'CocoaAsyncSocket' 13 | end 14 | -------------------------------------------------------------------------------- /ios-ntp-lib/ios-ntp.h: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ NetworkClock.h ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Oct17/10 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import "ntp-log.h" 8 | #import "NetAssociation.h" 9 | #import "NetworkClock.h" 10 | #import "NSDate+NetworkClock.h" 11 | -------------------------------------------------------------------------------- /ios-ntp-app/ntpAppDelegate.h: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ ntpAppDelegate.h ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Nov16/10 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import 8 | 9 | @interface ntpAppDelegate : UIResponder 10 | 11 | @property (strong, nonatomic) UIWindow * window; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'ios-lib' do 5 | pod 'CocoaAsyncSocket' 6 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 7 | # use_frameworks! 8 | 9 | # Pods for ios-lib 10 | 11 | end 12 | 13 | target 'ios_fwk' do 14 | pod 'CocoaAsyncSocket' 15 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 16 | # use_frameworks! 17 | 18 | # Pods for ios_fwk 19 | 20 | end 21 | 22 | target 'ntp-app' do 23 | 24 | pod 'CocoaAsyncSocket' 25 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 26 | # use_frameworks! 27 | 28 | # Pods for ntp-app 29 | 30 | end 31 | -------------------------------------------------------------------------------- /ios-ntp-app/ntpAppDelegate.m: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ ntpAppDelegate.m ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Nov16/10 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import "ntpAppDelegate.h" 8 | 9 | @implementation ntpAppDelegate 10 | 11 | - (BOOL) application:(UIApplication *) app didFinishLaunchingWithOptions:(NSDictionary *) options { 12 | 13 | return YES; 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /ios-ntp-app/main.m: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ main.m ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Oct17/10 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import 8 | #import "ntpAppDelegate.h" 9 | 10 | int main(int argc, char *argv[]) { 11 | 12 | @autoreleasepool { 13 | 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([ntpAppDelegate class])); 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /ntp-test/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios-ntp-rez/ios-ntp-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.1.9 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 000 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ios-ntp-app/ntpViewController.h: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ ntpViewController.h ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Nov28/14 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import 8 | #import "ios-ntp.h" 9 | 10 | @interface ntpViewController : UIViewController 11 | 12 | @property (weak, nonatomic) IBOutlet UILabel * sysClockLabel; 13 | @property (weak, nonatomic) IBOutlet UILabel * netClockLabel; 14 | @property (weak, nonatomic) IBOutlet UILabel * offsetLabel; 15 | 16 | @property (weak, nonatomic) IBOutlet UILabel * timeCheckLabel; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ios-ntp-lib/NSDate+NetworkClock.m: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ Author: Juan Batiz-Benet ║ 3 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 4 | 5 | #import "NSDate+NetworkClock.h" 6 | #import "NetworkClock.h" 7 | 8 | @implementation NSDate (NetworkClock) 9 | 10 | - (NSTimeInterval) timeIntervalSinceNetworkDate { 11 | return [self timeIntervalSinceDate:[NSDate networkDate]]; 12 | } 13 | 14 | + (NSTimeInterval) timeIntervalSinceNetworkDate { 15 | return [[self date] timeIntervalSinceNetworkDate]; 16 | } 17 | 18 | 19 | + (NSDate *) networkDate { 20 | return [NetworkClock sharedNetworkClock].networkTime; 21 | } 22 | 23 | + (NSDate *) threadsafeNetworkDate { 24 | NetworkClock *sharedClock = [NetworkClock sharedNetworkClock]; 25 | @synchronized(sharedClock) { 26 | return sharedClock.networkTime; 27 | } 28 | } 29 | 30 | @end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2012-2021, Ramsay Consulting 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to 6 | deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | sell copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /ios-ntp-lib/NSDate+NetworkClock.h: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ Author: Juan Batiz-Benet ║ 3 | ║ ║ 4 | ║ Category on NSDate to provide convenience access to NetworkClock. ║ 5 | ║ To use, simply call [NSDate networkDate]; ║ 6 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 7 | 8 | #import 9 | 10 | @interface NSDate (NetworkClock) 11 | 12 | @property (NS_NONATOMIC_IOSONLY, readonly) NSTimeInterval timeIntervalSinceNetworkDate; 13 | 14 | + (NSTimeInterval) timeIntervalSinceNetworkDate; 15 | 16 | + (NSDate *) networkDate; 17 | 18 | // the threadsafe version guards against reading a double that could be 19 | // potentially being updated at the same time. Since doubles are 8 words, 20 | // and arm is 32bit, this is not atomic and could provide bad values. 21 | 22 | + (NSDate *) threadsafeNetworkDate; 23 | 24 | @end -------------------------------------------------------------------------------- /ios-ntp-rez/ntp-app-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | ntp-app 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | UIApplicationExitsOnSuspend 30 | 31 | UIMainStoryboardFile 32 | Storyboard 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ios-ntp-lib/NetworkClock.h: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ NetworkClock.h ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Oct17/10 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import "NetAssociation.h" 8 | 9 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 10 | ┃ The NetworkClock sends notifications of the network time. It will attempt to provide a very ┃ 11 | ┃ early estimate and then refine that and reduce the number of notifications ... ┃ 12 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 13 | 14 | @interface NetworkClock : NSObject 15 | 16 | + (instancetype) sharedNetworkClock; 17 | 18 | - (void) createAssociations; 19 | - (void) createAssociationsWithServers:(NSArray *)servers; 20 | 21 | - (void) enableAssociations; 22 | - (void) snoozeAssociations; 23 | - (void) finishAssociations; 24 | 25 | @property (NS_NONATOMIC_IOSONLY, readonly, copy) NSDate * networkTime; 26 | @property (NS_NONATOMIC_IOSONLY, readonly) NSTimeInterval networkOffset; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ios-ntp-app/ntpViewController.m: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ ntpViewController.m ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Nov28/14 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import "ntpViewController.h" 8 | 9 | @interface ntpViewController () { 10 | 11 | NetworkClock * netClock; // complex clock 12 | NetAssociation * netAssociation; // one-time server 13 | 14 | } 15 | 16 | @end 17 | 18 | @implementation ntpViewController 19 | 20 | NSDateFormatter * dateFormatter; 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | dateFormatter = [[NSDateFormatter alloc] init]; 26 | dateFormatter.dateStyle = NSDateFormatterLongStyle; 27 | dateFormatter.timeStyle = NSDateFormatterMediumStyle; 28 | dateFormatter.locale = [NSLocale currentLocale]; 29 | 30 | netClock = [NetworkClock sharedNetworkClock]; 31 | 32 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 33 | │ Create a timer that will fire every second to refresh the text labels in the UI. │ 34 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 35 | NSTimer * repeatingTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1.0] 36 | interval:1.0 37 | target:self 38 | selector:@selector(timerFireMethod:) 39 | userInfo:nil 40 | repeats:YES]; 41 | 42 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 43 | │ Add the screen refresh repeating timer to the run-loop .. │ 44 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 45 | [[NSRunLoop currentRunLoop] addTimer:repeatingTimer 46 | forMode:NSDefaultRunLoopMode]; 47 | } 48 | 49 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 50 | ┃ The method executed by the timer -- gets the latest times and displays them. ┃ 51 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 52 | - (void) timerFireMethod:(NSTimer *) theTimer { 53 | _sysClockLabel.text = [NSString stringWithFormat:@"System Clock: %@", 54 | [dateFormatter stringFromDate:[NSDate date]]]; 55 | _netClockLabel.text = [NSString stringWithFormat:@"Network Clock: %@", 56 | [dateFormatter stringFromDate:netClock.networkTime]]; 57 | _offsetLabel.text = [NSString stringWithFormat:@"Clock Offet: %5.3f mSec", netClock.networkOffset * 1000.0]; 58 | } 59 | 60 | 61 | 62 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 63 | ┃ Gets a single NetAssociation and tells it to get the time from its server. ┃ 64 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 65 | - (IBAction) timeCheck:(id)sender { 66 | netAssociation = [[NetAssociation alloc] initWithServerName:[NetAssociation ipAddrFromName:@"time.apple.com"]]; 67 | netAssociation.delegate = self; 68 | [netAssociation sendTimeQuery]; 69 | } 70 | 71 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 72 | ┃ Called when that single NetAssociation has a network time to report. ┃ 73 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 74 | - (void) reportFromDelegate { 75 | _timeCheckLabel.text = [NSString stringWithFormat:@"System ahead by: %5.3f mSec", 76 | netAssociation.offset * 1000.0]; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /ios-ntp-lib/NetAssociation.h: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ NetAssociation.h ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Nov03/10 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ║──────────────────────────────────────────────────────────────────────────────────────────────────║ 6 | ║ This NetAssociation manages the communication and time calculations for one server. ║ 7 | ║ ║ 8 | ║ Multiple servers are used in a process in which each client/server pair (association) works to ║ 9 | ║ obtain its own best version of the time. The client sends small UDP packets to the server and ║ 10 | ║ the server overwrites certain fields in the packet and returns it immediately. As each packet ║ 11 | ║ is received, the offset between the client's network time and the system clock is derived with ║ 12 | ║ associated statistics. ║ 13 | ║ ║ 14 | ║ Each association makes a best effort at obtaining an accurate time and makes it available as a ║ 15 | ║ property. Another process may use this to select, cluster, and combine the various servers' ║ 16 | ║ data to determine the most accurate and reliable candidates to provide an overall best time. ║ 17 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 18 | 19 | #import 20 | #import "GCDAsyncUdpSocket.h" 21 | 22 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 23 | │ NTP Timestamp Structure │ 24 | │ │ 25 | │ 0 1 2 3 │ 26 | │ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 │ 27 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 28 | │ | Seconds | │ 29 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 30 | │ | Seconds Fraction (0-padded) | | | | | <-- 4294967296 = 1 second │ 31 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 32 | │ | | | | | | │ 33 | │ | | | | | 233 picoseconds │ 34 | │ | | | | 59.6 nanoseconds (mask = 0xffffff00) │ 35 | │ | | | 238 nanoseconds (mask = 0xfffffc00) │ 36 | │ | | 0.954 microsecond (mask = 0xfffff000) │ 37 | │ | 15.3 microseconds (mask = 0xffff0000) │ 38 | │ 3.9 milliseconds (mask = 0xff000000) │ 39 | │ │ 40 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 41 | 42 | #define JAN_1970 ((uint64_t)0x83aa7e80) // UNIX epoch in NTP's epoch: 43 | // 1970-1900 (2,208,988,800s) 44 | union ntpTime { 45 | 46 | struct { 47 | uint32_t fractSeconds; 48 | uint32_t wholeSeconds; 49 | } partials; 50 | 51 | uint64_t floating; 52 | 53 | } ; 54 | 55 | union ntpTime ntp_time_now(void); 56 | union ntpTime unix2ntp(const struct timeval * tv); 57 | double ntpDiffSeconds(union ntpTime * start, union ntpTime * stop); 58 | 59 | @protocol NetAssociationDelegate 60 | 61 | - (void) reportFromDelegate; 62 | 63 | @end 64 | 65 | @protocol GCDAsyncUdpSocketDelegate; 66 | 67 | @interface NetAssociation : NSObject 68 | 69 | @property (nonatomic, weak) id delegate; 70 | 71 | @property (readonly) NSString * server; // server address "123.45.67.89" 72 | @property (readonly) BOOL active; // is this clock running yet? 73 | @property (readonly) BOOL trusty; // is this clock trustworthy 74 | @property (readonly) double offset; // offset from device time (secs) 75 | 76 | - (instancetype) init NS_UNAVAILABLE; 77 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 78 | ┃ create a NetAssociation with the provided server name .. just sitting idle .. ┃ 79 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 80 | - (instancetype) initWithServerName:(NSString *) serverName NS_DESIGNATED_INITIALIZER; 81 | 82 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 83 | ┃ empty the time values fifo and start the timer which queries the association's server .. ┃ 84 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 85 | - (void) enable; // .. 86 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 87 | ┃ snooze: stop the timer in a way that let's start it again .. ┃ 88 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 89 | - (void) snooze; // stop the timer but don't delete it 90 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 91 | ┃ finish: stop the timer and invalidate it .. it'll die and disappear .. ┃ 92 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 93 | - (void) finish; // .. 94 | 95 | - (void) sendTimeQuery; // send one datagram to server .. 96 | 97 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 98 | ┃ utility method converts domain name to numeric dotted address string .. ┃ 99 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 100 | + (NSString *) ipAddrFromName: (NSString *) domainName; 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /ios-ntp-lib/Notes: -------------------------------------------------------------------------------- 1 | *** This table lookup algorithm is from the orginal NTP source code 2 | 3 | /* 4 | * Tables to calculate time stamp fractions from usecs. The entries 5 | * in these tables are offset into using each of the two low order 6 | * bytes plus the next 4 bits in a usec value (from a struct timeval). 7 | * These are summed to produce the time stamp fraction. 8 | * 9 | * Note that these tables are rounded (not truncated) to the nearest 10 | * low order bit in the fraction. The timestamp computed should be 11 | * +- 1.5 low order bits. 12 | */ 13 | 14 | unsigned long microSec2FractSec_Low[256] = { 15 | 0x00000000, 0x000010c7, 0x0000218e, 0x00003255, 16 | 0x0000431c, 0x000053e3, 0x000064aa, 0x00007571, 17 | 0x00008638, 0x000096ff, 0x0000a7c6, 0x0000b88d, 18 | 0x0000c954, 0x0000da1b, 0x0000eae2, 0x0000fba9, 19 | 0x00010c6f, 0x00011d36, 0x00012dfd, 0x00013ec4, 20 | 0x00014f8b, 0x00016052, 0x00017119, 0x000181e0, 21 | 0x000192a7, 0x0001a36e, 0x0001b435, 0x0001c4fc, 22 | 0x0001d5c3, 0x0001e68a, 0x0001f751, 0x00020818, 23 | 0x000218df, 0x000229a6, 0x00023a6d, 0x00024b34, 24 | 0x00025bfb, 0x00026cc2, 0x00027d89, 0x00028e50, 25 | 0x00029f17, 0x0002afde, 0x0002c0a5, 0x0002d16c, 26 | 0x0002e233, 0x0002f2fa, 0x000303c0, 0x00031487, 27 | 0x0003254e, 0x00033615, 0x000346dc, 0x000357a3, 28 | 0x0003686a, 0x00037931, 0x000389f8, 0x00039abf, 29 | 0x0003ab86, 0x0003bc4d, 0x0003cd14, 0x0003dddb, 30 | 0x0003eea2, 0x0003ff69, 0x00041030, 0x000420f7, 31 | 0x000431be, 0x00044285, 0x0004534c, 0x00046413, 32 | 0x000474da, 0x000485a1, 0x00049668, 0x0004a72f, 33 | 0x0004b7f6, 0x0004c8bd, 0x0004d984, 0x0004ea4b, 34 | 0x0004fb12, 0x00050bd8, 0x00051c9f, 0x00052d66, 35 | 0x00053e2d, 0x00054ef4, 0x00055fbb, 0x00057082, 36 | 0x00058149, 0x00059210, 0x0005a2d7, 0x0005b39e, 37 | 0x0005c465, 0x0005d52c, 0x0005e5f3, 0x0005f6ba, 38 | 0x00060781, 0x00061848, 0x0006290f, 0x000639d6, 39 | 0x00064a9d, 0x00065b64, 0x00066c2b, 0x00067cf2, 40 | 0x00068db9, 0x00069e80, 0x0006af47, 0x0006c00e, 41 | 0x0006d0d5, 0x0006e19c, 0x0006f263, 0x00070329, 42 | 0x000713f0, 0x000724b7, 0x0007357e, 0x00074645, 43 | 0x0007570c, 0x000767d3, 0x0007789a, 0x00078961, 44 | 0x00079a28, 0x0007aaef, 0x0007bbb6, 0x0007cc7d, 45 | 0x0007dd44, 0x0007ee0b, 0x0007fed2, 0x00080f99, 46 | 0x00082060, 0x00083127, 0x000841ee, 0x000852b5, 47 | 0x0008637c, 0x00087443, 0x0008850a, 0x000895d1, 48 | 0x0008a698, 0x0008b75f, 0x0008c826, 0x0008d8ed, 49 | 0x0008e9b4, 0x0008fa7b, 0x00090b41, 0x00091c08, 50 | 0x00092ccf, 0x00093d96, 0x00094e5d, 0x00095f24, 51 | 0x00096feb, 0x000980b2, 0x00099179, 0x0009a240, 52 | 0x0009b307, 0x0009c3ce, 0x0009d495, 0x0009e55c, 53 | 0x0009f623, 0x000a06ea, 0x000a17b1, 0x000a2878, 54 | 0x000a393f, 0x000a4a06, 0x000a5acd, 0x000a6b94, 55 | 0x000a7c5b, 0x000a8d22, 0x000a9de9, 0x000aaeb0, 56 | 0x000abf77, 0x000ad03e, 0x000ae105, 0x000af1cc, 57 | 0x000b0292, 0x000b1359, 0x000b2420, 0x000b34e7, 58 | 0x000b45ae, 0x000b5675, 0x000b673c, 0x000b7803, 59 | 0x000b88ca, 0x000b9991, 0x000baa58, 0x000bbb1f, 60 | 0x000bcbe6, 0x000bdcad, 0x000bed74, 0x000bfe3b, 61 | 0x000c0f02, 0x000c1fc9, 0x000c3090, 0x000c4157, 62 | 0x000c521e, 0x000c62e5, 0x000c73ac, 0x000c8473, 63 | 0x000c953a, 0x000ca601, 0x000cb6c8, 0x000cc78f, 64 | 0x000cd856, 0x000ce91d, 0x000cf9e4, 0x000d0aaa, 65 | 0x000d1b71, 0x000d2c38, 0x000d3cff, 0x000d4dc6, 66 | 0x000d5e8d, 0x000d6f54, 0x000d801b, 0x000d90e2, 67 | 0x000da1a9, 0x000db270, 0x000dc337, 0x000dd3fe, 68 | 0x000de4c5, 0x000df58c, 0x000e0653, 0x000e171a, 69 | 0x000e27e1, 0x000e38a8, 0x000e496f, 0x000e5a36, 70 | 0x000e6afd, 0x000e7bc4, 0x000e8c8b, 0x000e9d52, 71 | 0x000eae19, 0x000ebee0, 0x000ecfa7, 0x000ee06e, 72 | 0x000ef135, 0x000f01fb, 0x000f12c2, 0x000f2389, 73 | 0x000f3450, 0x000f4517, 0x000f55de, 0x000f66a5, 74 | 0x000f776c, 0x000f8833, 0x000f98fa, 0x000fa9c1, 75 | 0x000fba88, 0x000fcb4f, 0x000fdc16, 0x000fecdd, 76 | 0x000ffda4, 0x00100e6b, 0x00101f32, 0x00102ff9, 77 | 0x001040c0, 0x00105187, 0x0010624e, 0x00107315, 78 | 0x001083dc, 0x001094a3, 0x0010a56a, 0x0010b631, 79 | }; 80 | 81 | unsigned long microSec2FractSec_Mid[256] = { 82 | 0x00000000, 0x0010c6f8, 0x00218def, 0x003254e7, 83 | 0x00431bde, 0x0053e2d6, 0x0064a9ce, 0x007570c5, 84 | 0x008637bd, 0x0096feb4, 0x00a7c5ac, 0x00b88ca4, 85 | 0x00c9539b, 0x00da1a93, 0x00eae18a, 0x00fba882, 86 | 0x010c6f7a, 0x011d3671, 0x012dfd69, 0x013ec460, 87 | 0x014f8b58, 0x01605250, 0x01711947, 0x0181e03f, 88 | 0x0192a736, 0x01a36e2e, 0x01b43526, 0x01c4fc1d, 89 | 0x01d5c315, 0x01e68a0c, 0x01f75104, 0x020817fc, 90 | 0x0218def3, 0x0229a5eb, 0x023a6ce3, 0x024b33da, 91 | 0x025bfad2, 0x026cc1c9, 0x027d88c1, 0x028e4fb9, 92 | 0x029f16b0, 0x02afdda8, 0x02c0a49f, 0x02d16b97, 93 | 0x02e2328f, 0x02f2f986, 0x0303c07e, 0x03148775, 94 | 0x03254e6d, 0x03361565, 0x0346dc5c, 0x0357a354, 95 | 0x03686a4b, 0x03793143, 0x0389f83b, 0x039abf32, 96 | 0x03ab862a, 0x03bc4d21, 0x03cd1419, 0x03dddb11, 97 | 0x03eea208, 0x03ff6900, 0x04102ff7, 0x0420f6ef, 98 | 0x0431bde7, 0x044284de, 0x04534bd6, 0x046412cd, 99 | 0x0474d9c5, 0x0485a0bd, 0x049667b4, 0x04a72eac, 100 | 0x04b7f5a3, 0x04c8bc9b, 0x04d98393, 0x04ea4a8a, 101 | 0x04fb1182, 0x050bd879, 0x051c9f71, 0x052d6669, 102 | 0x053e2d60, 0x054ef458, 0x055fbb4f, 0x05708247, 103 | 0x0581493f, 0x05921036, 0x05a2d72e, 0x05b39e25, 104 | 0x05c4651d, 0x05d52c15, 0x05e5f30c, 0x05f6ba04, 105 | 0x060780fb, 0x061847f3, 0x06290eeb, 0x0639d5e2, 106 | 0x064a9cda, 0x065b63d2, 0x066c2ac9, 0x067cf1c1, 107 | 0x068db8b8, 0x069e7fb0, 0x06af46a8, 0x06c00d9f, 108 | 0x06d0d497, 0x06e19b8e, 0x06f26286, 0x0703297e, 109 | 0x0713f075, 0x0724b76d, 0x07357e64, 0x0746455c, 110 | 0x07570c54, 0x0767d34b, 0x07789a43, 0x0789613a, 111 | 0x079a2832, 0x07aaef2a, 0x07bbb621, 0x07cc7d19, 112 | 0x07dd4410, 0x07ee0b08, 0x07fed200, 0x080f98f7, 113 | 0x08205fef, 0x083126e6, 0x0841edde, 0x0852b4d6, 114 | 0x08637bcd, 0x087442c5, 0x088509bc, 0x0895d0b4, 115 | 0x08a697ac, 0x08b75ea3, 0x08c8259b, 0x08d8ec92, 116 | 0x08e9b38a, 0x08fa7a82, 0x090b4179, 0x091c0871, 117 | 0x092ccf68, 0x093d9660, 0x094e5d58, 0x095f244f, 118 | 0x096feb47, 0x0980b23e, 0x09917936, 0x09a2402e, 119 | 0x09b30725, 0x09c3ce1d, 0x09d49514, 0x09e55c0c, 120 | 0x09f62304, 0x0a06e9fb, 0x0a17b0f3, 0x0a2877ea, 121 | 0x0a393ee2, 0x0a4a05da, 0x0a5accd1, 0x0a6b93c9, 122 | 0x0a7c5ac1, 0x0a8d21b8, 0x0a9de8b0, 0x0aaeafa7, 123 | 0x0abf769f, 0x0ad03d97, 0x0ae1048e, 0x0af1cb86, 124 | 0x0b02927d, 0x0b135975, 0x0b24206d, 0x0b34e764, 125 | 0x0b45ae5c, 0x0b567553, 0x0b673c4b, 0x0b780343, 126 | 0x0b88ca3a, 0x0b999132, 0x0baa5829, 0x0bbb1f21, 127 | 0x0bcbe619, 0x0bdcad10, 0x0bed7408, 0x0bfe3aff, 128 | 0x0c0f01f7, 0x0c1fc8ef, 0x0c308fe6, 0x0c4156de, 129 | 0x0c521dd5, 0x0c62e4cd, 0x0c73abc5, 0x0c8472bc, 130 | 0x0c9539b4, 0x0ca600ab, 0x0cb6c7a3, 0x0cc78e9b, 131 | 0x0cd85592, 0x0ce91c8a, 0x0cf9e381, 0x0d0aaa79, 132 | 0x0d1b7171, 0x0d2c3868, 0x0d3cff60, 0x0d4dc657, 133 | 0x0d5e8d4f, 0x0d6f5447, 0x0d801b3e, 0x0d90e236, 134 | 0x0da1a92d, 0x0db27025, 0x0dc3371d, 0x0dd3fe14, 135 | 0x0de4c50c, 0x0df58c03, 0x0e0652fb, 0x0e1719f3, 136 | 0x0e27e0ea, 0x0e38a7e2, 0x0e496ed9, 0x0e5a35d1, 137 | 0x0e6afcc9, 0x0e7bc3c0, 0x0e8c8ab8, 0x0e9d51b0, 138 | 0x0eae18a7, 0x0ebedf9f, 0x0ecfa696, 0x0ee06d8e, 139 | 0x0ef13486, 0x0f01fb7d, 0x0f12c275, 0x0f23896c, 140 | 0x0f345064, 0x0f45175c, 0x0f55de53, 0x0f66a54b, 141 | 0x0f776c42, 0x0f88333a, 0x0f98fa32, 0x0fa9c129, 142 | 0x0fba8821, 0x0fcb4f18, 0x0fdc1610, 0x0fecdd08, 143 | 0x0ffda3ff, 0x100e6af7, 0x101f31ee, 0x102ff8e6, 144 | 0x1040bfde, 0x105186d5, 0x10624dcd, 0x107314c4, 145 | 0x1083dbbc, 0x1094a2b4, 0x10a569ab, 0x10b630a3, 146 | }; 147 | 148 | unsigned long microSec2FractSec_Top[16] = { 149 | 0x00000000, 0x10c6f79a, 0x218def35, 0x3254e6cf, 150 | 0x431bde6a, 0x53e2d604, 0x64a9cd9f, 0x7570c539, 151 | 0x8637bcd3, 0x96feb46e, 0xa7c5ac08, 0xb88ca3a3, 152 | 0xc9539b3d, 0xda1a92d7, 0xeae18a72, 0xfba8820c, 153 | }; 154 | 155 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 156 | │ Convert from Unix time to NTP time │ 157 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 158 | void unix2ntpX(const struct timeval * tv, struct ntpTimestamp * ntp) { 159 | ntp->wholeSeconds = (uint32_t)(tv->tv_sec + JAN_1970); 160 | ntp->fractSeconds = (uint32_t)(microSec2FractSec_Low[ ((tv)->tv_usec) & 0xff] + 161 | microSec2FractSec_Mid[(((tv)->tv_usec) >> 8) & 0xff] + 162 | microSec2FractSec_Top[(((tv)->tv_usec) >> 16) & 0xf]); 163 | } 164 | 165 | 166 | 167 | *** 168 | 169 | struct timeval now; 170 | gettimeofday(&now, (struct timezone *)NULL);; 171 | 172 | NSLog(@"%010ld.%06d <--- original", now.tv_sec, now.tv_usec); 173 | 174 | struct ntpTimestamp ntp; 175 | 176 | unix2ntp(&now, &ntp); 177 | 178 | struct timeval tempTime; 179 | ntp2unix(&ntp, &tempTime); 180 | 181 | NSLog(@"%010u.%06d (%@) <--- unix2ntp (old)", 182 | ntp.wholeSeconds, 183 | tempTime.tv_usec, 184 | [self dateFromNetworkTime:&ntp]); 185 | 186 | NSLog(@"%010ld.%06d <--- unix2ntp (old)", tempTime.tv_sec, tempTime.tv_usec); 187 | 188 | unix2ntpX(&now, &ntp); 189 | 190 | ntp2unix(&ntp, &tempTime); 191 | 192 | NSLog(@"%010u.%06d (%@) <--- unix2ntp (new)", 193 | ntp.wholeSeconds, 194 | tempTime.tv_usec, 195 | [self dateFromNetworkTime:&ntp]); 196 | 197 | NSLog(@"%010ld.%06d <--- unix2ntp (new)\n-------------------------------", 198 | tempTime.tv_sec, tempTime.tv_usec); 199 | 200 | *** 201 | 202 | struct timeval now1; 203 | struct timeval now2; 204 | 205 | gettimeofday(&now1, (struct timezone *)NULL); 206 | now2.tv_sec = now1.tv_sec + 1L; 207 | now2.tv_usec = now1.tv_usec + 1L; 208 | 209 | struct ntpTimestamp time1; 210 | struct ntpTimestamp time2; 211 | 212 | unix2ntp(&now1, &time1); 213 | unix2ntp(&now2, &time2); 214 | 215 | double t21 = ntpDiffSeconds(&time1, &time2); // .. (T2-T1) 216 | 217 | NSLog(@"0.0 -- %f", t21); 218 | 219 | *** 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ios-ntp 2 | 3 | A network time protocol client (and an application testbed for iOS). 4 | This project is no longer being worked on, but issues will be responded to. 5 | 6 | Created by Gavin Eadie on Oct 17, 2010 7 | 8 | ### News 9 | **June 4, 2018:** (version 1.1.9) There was a conflict when using cocoasyncsocket and ios-ntp; 10 | added pod dependency and removed asyncsocket files from network-lib. The necessary files can be 11 | found at https://github.com/robbiehanson/CocoaAsyncSocket 12 | 13 | **January 24, 2018:** (version 1.1.6) improvements have been made in a few areas: 14 | 15 | * a podspec target for tvOS has been added. 16 | * the files from `CocoaAsyncSocket` have been replaced with the most recent versions. 17 | 18 | **December 20, 2016:** (version 1.1.4) improvements have been made in a few areas: 19 | 20 | * the use of pool ntp server host names is strongly discouraged so they have been removed from this code and documentation. 21 | Read the NTP Pool Project page at http://www.pool.ntp.org/vendors.html for context. NOTE: The library will query NO servers 22 | in its new default state .. now a `ntp.hosts` file MUST be provided. 23 | 24 | **February 1, 2016:** (version 1.1.3) improvements have been made in a few areas: 25 | 26 | * arithmetic operating on an NTP 64-bit time has been improved slightly. 27 | * the delegate callback from `NetAssocation` now runs on the main thread, which allows it to modify 28 | any UI component (illegal from a background thread). 29 | * a "receive packet filter" has been added, but not yet invoked. This will used to drop UPD 30 | packets that don't pass validation. 31 | * `[NetAssociation finish]` now invalidates its timer so that association plays no further part in time derivation. 32 | * upgrade sources to most recent Objective-C conventions. 33 | 34 | _Getting a Quick Timecheck_ 35 | 36 | `ios-ntp` is often (mostly?) used to make sure someone hasn't fiddled with the system clock. The complications 37 | involved in using multiple servers and averaging time offsets is overkill for this purpose. The following skeleton 38 | code is all that is needed to check the time. If you want some more assurance of accuracy, repeat the operation 39 | a few time; if you want to continue to watch the clock, you might invoke this at infrequent intervals: 40 | 41 | #import "ios-ntp.h" 42 | 43 | @interface ntpViewController : UIViewController 44 | 45 | @end 46 | 47 | @implementation ntpViewController 48 | - (void)viewDidLoad { 49 | [super viewDidLoad]; 50 | 51 | netAssociation = [[NetAssociation alloc] 52 | initWithServerName:[NetAssociation ipAddrFromName:@"time.apple.com"]]; 53 | netAssociation.delegate = self; 54 | [netAssociation sendTimeQuery]; 55 | } 56 | 57 | - (void) reportFromDelegate { 58 | printf("time offset: %5.3f mSec", netAssociation.offset * 1000.0]; 59 | } 60 | ____ 61 | 62 | **January 17, 2016:** (version 1.1.2) minor cleanup for Xcode 7.x 63 | 64 | **July 22, 2015:** (version 1.1.1) `ios-ntp` has contained a resource file 65 | (called `ntp.hosts`) which contained a list of time server hosts to be used 66 | for querying the time. That file has been removed in this release. 67 | 68 | The logic is that, since `ios-ntp` can now be added to a project via CocoaPods, 69 | any local changes made to that file will be overwritten the next time the `ios-ntp` 70 | pod is updated and, since `ios-ntp` already contains a built-in list of time servers, 71 | removing this file from the pod should not impact the behavior of the `ios-ntp` code. 72 | 73 | If you want to use your own list of time servers, you need to create a file containing 74 | time host names, one per line, name it `ntp.hosts` and place it in the main bundle of your 75 | application (the sample app `ios-ntp-app` does this to use the server at `time.apple.com`). 76 | 77 | **June 10, 2015:** (version 1.1) I recently discovered a re-entrancy bug when John 78 | Grismore brought my attention to inaccuracies in reported network time offsets. 79 | When a NetAssociation notified the NetClock that it had a new time offset, that 80 | event might interrupt the offset averaging that NetClock does causing the 81 | averaging to break. 82 | 83 | In fact, this mechanism isn't optimal anyway! The notifications that cause 84 | offset averaging arrive at NetClock constantly whether the result is used or 85 | not. We're keeping the NetClock network time offset property up to date whether 86 | we need it or not. Better would be to perform the averaging only when the 87 | offset NetClock property is called for, and that is how ios-ntp now works. 88 | 89 | The API is not changed, so your application should require no changes. 90 | 91 | **February 22, 2015:** Several important changes have been made 92 | including one that will be helpful for those who want to get a quick 93 | one-time value of the difference between system time and network time. 94 | 95 | Before this change, ios-ntp would use time estimates from a set 96 | of NetAssociations (one per time servers), constantly determining the best 97 | time by sampling these values. This is the model for computers which 98 | have a continuous low level task monitoring the time. Application in 99 | iOS often have a different need; they are more likely to want an fast 100 | estimate of the time on demand. To provide the ability to the developer, 101 | access has been provided to use a NetAssociations directly 102 | 103 | An NetAssociation can now be asked for one measure of the time 104 | from one time server so an iOS app can create an NetAssociation, use 105 | it to get the time, and be done. 106 | 107 | This code operates on 32-bit and 64-bit iOS devices. 108 | 109 | This code **requires** iOS 7, or higher. 110 | 111 | ---- 112 | ### About 113 | 114 | The clock on the oldest iPhone, iTouch or iPad is not closely 115 | synchronized to the correct time. In the case of a device which is 116 | obtaining its time from the telephone system, there is a setting to 117 | enable synchronizing to the phone company time, but that time has been 118 | known to be over a minute different from the correct time. 119 | 120 | **Note**: Recent versions of iOS have NTP time derivation built in 121 | so that the system clock now varies from 'real time' by less than one 122 | second (it's usually accurate to about 10mS). 123 | 124 | In addition, users may change their device time and severely affect 125 | applications that rely on correct times to enforce functionality, or may 126 | set their devices clock into the past in an attempt to dodge an expiry 127 | date. 128 | 129 | This project contains code to provide time obtained from standard time 130 | servers using the simple network time protocol (SNTP: RFC 5905). The 131 | implementation is not a rigorous as described in that document since the 132 | goal was to improve time accuracy to tens of milliSeconds, not to 133 | microseconds. 134 | 135 | Computers using the NTP protocol usually employ it in a continuous low 136 | level task to keep track of the time on a continuous basis. A 137 | background application uses occasional time estimates from a set of time 138 | servers to determine the best time by sampling these values over time. 139 | iOS applications are different, being more likely to want a one-time, 140 | quick estimate of the time. 141 | 142 | ios-ntp provides both the continuous and on-demand modes of operation. 143 | The continuous mode uses multiple 'associations' with time servers which 144 | use timers to repeatedly obtain time estimates. These associations can, 145 | however, be used by the developer to get one time from one server. 146 | 147 | ### Usage 148 | 149 | The code can be incorporated as source code or as a framework in an 150 | Xcode project. The framework usage is temporarily unavailable but will 151 | be restored soon. 152 | 153 | _More to come about using a framework._ 154 | 155 | Download the [ios-ntp](http://github.com/jbenet/ios-ntp) project, add 156 | the necessary to your project, build and run. You will need: 157 | 158 | #import "ios-ntp.h" 159 | 160 | where ios-ntp is referenced. 161 | 162 | ##### Continuous Mode 163 | 164 | Simply create a `NetworkClock`. As soon as you create it, the NTP 165 | process will begin polling the time servers in the "ntp.hosts" file. 166 | You may wish to start it when the application starts, so that the time is 167 | well synchronized by the time you actually want to use it, just call it 168 | in your AppDelegate's `didFinishLaunching` method.: 169 | 170 | NetworkClock * nc = [NetworkClock sharedNetworkClock]; 171 | 172 | then wait at least ten seconds for some time servers to respond before 173 | calling: 174 | 175 | NSDate * nt = nc.networkTime; 176 | 177 | It will take about one minute before untrustworthy servers start to get 178 | dropped from the pool. 179 | 180 | _It would probably be better if NetworkClock called back to a delegate 181 | method, like NetAssociation does below, when it had a good time but 182 | that's not how it works, yet, so you have to wait till things settle 183 | down._ 184 | 185 | ##### On Demand Mode 186 | 187 | This usage is slightly more complicated. The developer must create an 188 | `NetAssociation` (with some specified time server), and then tell it get the 189 | time from that server. The association uses a delegate method to return 190 | itself with time information. 191 | 192 | netAssociation = [[NetAssociation alloc] initWithServerName:@"time.apple.com"]; 193 | netAssociation.delegate = self; 194 | [netAssociation sendTimeQuery]; 195 | 196 | ... 197 | 198 | - (void) reportFromDelegate { 199 | double timeOffset = netAssociation.offset; 200 | } 201 | 202 | ### Performance 203 | 204 | iOS is an event driven system with an emphasis 205 | on rapid response to gestures at the cost of other activity. This 206 | encourages the extensive use of design patterns like notification and 207 | delegation so, I think, the calculation of small time differences in this 208 | environment suffers as a result. 209 | 210 | ### License 211 | 212 | The [MIT](http://www.opensource.org/licenses/mit-license.php) 213 | License Copyright (c) 2010-2019, Ramsay Consulting 214 | 215 | ### History 216 | 217 | **November 19, 2014:** A large update was made today to bring ios-ntp 218 | into the modern world. The changes do include one bug fix, but are 219 | mostly related to making the code comply with the recent Xcode changes 220 | and requirements. 221 | 222 | Finally, note that this code was first written when there were only 223 | 32-bit iOS devices. As I write this there are still 32-bit devices which 224 | run the latest version of iOS (iPhone 4S, for example), but all newer 225 | iOS devices have a 64-bit architecture (iPhone 6, for example), and 226 | Apple requires that this be supported. 227 | -------------------------------------------------------------------------------- /ios-ntp-lib/NetworkClock.m: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ NetworkClock.m ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Oct17/10 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import 8 | 9 | #import "NetworkClock.h" 10 | #import "ntp-log.h" 11 | #import "GCDAsyncUdpSocket.h" 12 | 13 | @interface NetworkClock () { 14 | 15 | NSMutableArray * timeAssociations; 16 | 17 | NSArray * sortDescriptors; 18 | NSSortDescriptor * dispersionSortDescriptor; 19 | 20 | dispatch_queue_t associationDelegateQueue; 21 | 22 | } 23 | 24 | @end 25 | 26 | #pragma mark - 27 | #pragma mark N E T W O R K • C L O C K 28 | 29 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 30 | ┃ NetworkClock is a singleton class which will provide the best estimate of the difference in time ┃ 31 | ┃ between the device's system clock and the time returned by a collection of time servers. ┃ 32 | ┃ ┃ 33 | ┃ The method returns an NSDate with the network time. ┃ 34 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 35 | 36 | @implementation NetworkClock 37 | 38 | + (instancetype) sharedNetworkClock { 39 | static id sharedNetworkClockInstance = nil; 40 | static dispatch_once_t onceToken; 41 | 42 | dispatch_once(&onceToken, ^{ 43 | sharedNetworkClockInstance = [[self alloc] init]; 44 | }); 45 | 46 | return sharedNetworkClockInstance; 47 | } 48 | 49 | - (instancetype) init { 50 | if (self = [super init]) { 51 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 52 | │ Prepare a sort-descriptor to sort associations based on their dispersion, and then create an │ 53 | │ empty array for associations to fill .. │ 54 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 55 | sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:@"dispersion" ascending:YES]]; 56 | timeAssociations = [NSMutableArray arrayWithCapacity:100]; 57 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 58 | │ .. and fill that array with the time hosts obtained from "ntp.hosts" (or built-ins if absent) .. │ 59 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 60 | [[[NSOperationQueue alloc] init] addOperation:[[NSInvocationOperation alloc] 61 | initWithTarget:self 62 | selector:@selector(createAssociations) 63 | object:nil]]; 64 | } 65 | 66 | return self; 67 | } 68 | 69 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 70 | ┃ Return the offset to network-derived UTC. ┃ 71 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 72 | - (NSTimeInterval) networkOffset { 73 | 74 | if (timeAssociations.count == 0) return 0.0; 75 | 76 | NSArray * sortedArray = [timeAssociations sortedArrayUsingDescriptors:sortDescriptors]; 77 | 78 | double timeInterval = 0.0; 79 | short usefulCount = 0; 80 | 81 | for (NetAssociation * timeAssociation in sortedArray) { 82 | if (timeAssociation.active) { 83 | if (timeAssociation.trusty) { 84 | usefulCount++; 85 | timeInterval = timeInterval + timeAssociation.offset; 86 | // NSLog(@"[%@]: %f (%d)", timeAssociation.server, timeAssociation.offset*1000.0, usefulCount); 87 | } 88 | else { 89 | if (timeAssociations.count > 8) { 90 | NSLog(@"Clock•Drop: [%@]", timeAssociation.server); 91 | [timeAssociations removeObject:timeAssociation]; 92 | [timeAssociation finish]; 93 | } 94 | } 95 | 96 | if (usefulCount == 8) break; // use 8 best dispersions 97 | } 98 | } 99 | 100 | if (usefulCount > 0) { 101 | timeInterval = timeInterval / usefulCount; 102 | // NSLog(@"timeIntervalSinceDeviceTime: %f (%d)", timeInterval*1000.0, usefulCount); 103 | } 104 | 105 | return timeInterval; 106 | } 107 | 108 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 109 | ┃ Return the device clock time adjusted for the offset to network-derived UTC. ┃ 110 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 111 | - (NSDate *) networkTime { 112 | return [[NSDate date] dateByAddingTimeInterval:-self.networkOffset]; 113 | } 114 | 115 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 116 | ┃ Use the following time servers or, if it exists, read the "ntp.hosts" file from the application ┃ 117 | ┃ resources and derive all the IP addresses referred to, remove any duplicates and create an ┃ 118 | ┃ 'association' (individual host client) for each one. ┃ 119 | ┃──────────────────────────────────────────────────────────────────────────────────────────────────┃ 120 | ┃ PLEASE NOTE: The use of pool ntp server host names is strongly discouraged, see this page: ┃ 121 | ┃ http://www.pool.ntp.org/vendors.html ┃ 122 | ┃ ┃ 123 | ┃ To help resolve this problem, the list of pool server host names that used to be here has been ┃ 124 | ┃ removed. Code using this library inappropriately caused problems for the ntp community and, as ┃ 125 | ┃ a good net citizen, I'm sorry that this happened and am complying with requests to adhere to the ┃ 126 | ┃ norms of that community. All references to pool server host names have been removed and a link ┃ 127 | ┃ to the community page added. ┃ 128 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 129 | - (void) createAssociations { 130 | [self createAssociationsWithServers:@[]]; 131 | } 132 | 133 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 134 | ┃ Use the following time servers or, if it exists, read the "ntp.hosts" file from the application ┃ 135 | ┃ resources and derive all the IP addresses referred to, remove any duplicates and create an ┃ 136 | ┃ 'association' (individual host client) for each one. ┃ 137 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 138 | - (void) createAssociationsWithServers:(NSArray *)servers { 139 | NSArray * ntpDomains; 140 | NSString * filePath = [[NSBundle mainBundle] pathForResource:@"ntp.hosts" ofType:@""]; 141 | if (nil == filePath) { 142 | ntpDomains = servers; 143 | } 144 | else { 145 | NSString * fileData = [[NSString alloc] initWithData:[[NSFileManager defaultManager] 146 | contentsAtPath:filePath] 147 | encoding:NSUTF8StringEncoding]; 148 | 149 | ntpDomains = [fileData componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; 150 | } 151 | 152 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 153 | │ for each NTP service domain name in the 'ntp.hosts' file : "time.vendor.org" etc ... │ 154 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 155 | NSMutableSet * hostAddresses = [NSMutableSet setWithCapacity:100]; 156 | 157 | for (NSString * ntpDomainName in ntpDomains) { 158 | if (ntpDomainName.length == 0 || 159 | [ntpDomainName characterAtIndex:0] == ' ' || 160 | [ntpDomainName characterAtIndex:0] == '#') { 161 | continue; 162 | } 163 | 164 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 165 | │ ... resolve the IP address of the named host : "time.vendor.org" --> [123.45.67.89], ... │ 166 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 167 | CFHostRef ntpHostName = CFHostCreateWithName (nil, (__bridge CFStringRef)ntpDomainName); 168 | if (nil == ntpHostName) { 169 | NTP_Logging(@"CFHostCreateWithName for %@", ntpDomainName); 170 | continue; // couldn't create 'host object' ... 171 | } 172 | 173 | CFStreamError nameError; 174 | if (!CFHostStartInfoResolution (ntpHostName, kCFHostAddresses, &nameError)) { 175 | NTP_Logging(@"CFHostStartInfoResolution error %i for %@", (int)nameError.error, ntpDomainName); 176 | CFRelease(ntpHostName); 177 | continue; // couldn't start resolution ... 178 | } 179 | 180 | Boolean nameFound; 181 | NSArray * ntpHostAddrs = (__bridge NSArray *)(CFHostGetAddressing (ntpHostName, &nameFound)); 182 | 183 | if (!nameFound) { 184 | NTP_Logging(@"CFHostGetAddressing: %@ NOT resolved", ntpHostName); 185 | CFRelease(ntpHostName); 186 | continue; // resolution failed ... 187 | } 188 | 189 | if (ntpHostAddrs == nil) { 190 | NTP_Logging(@"CFHostGetAddressing: no addresses resolved for %@", ntpHostName); 191 | CFRelease(ntpHostName); 192 | continue; // NO addresses were resolved ... 193 | } 194 | CFRelease(ntpHostName); 195 | 196 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 197 | │ for each (sockaddr structure wrapped by a CFDataRef/NSData *) associated with the hostname, │ 198 | │ drop the IP address string into a Set to remove duplicates. │ 199 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 200 | for (NSData * ntpHost in ntpHostAddrs) { 201 | [hostAddresses addObject:[GCDAsyncUdpSocket hostFromAddress:ntpHost]]; 202 | } 203 | } 204 | 205 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 206 | │ ... now start one 'association' (network clock server) for each address. │ 207 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 208 | for (NSString * server in hostAddresses) { 209 | [timeAssociations addObject:[[NetAssociation alloc] initWithServerName:server]]; 210 | } 211 | 212 | [self enableAssociations]; 213 | } 214 | 215 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 216 | ┃ .. ┃ 217 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 218 | - (void) enableAssociations { 219 | 220 | for (NetAssociation * timeAssociation in timeAssociations) [timeAssociation enable]; 221 | 222 | } 223 | 224 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 225 | ┃ Stop all the individual ntp clients associations .. ┃ 226 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 227 | - (void) snoozeAssociations { 228 | 229 | for (NetAssociation * timeAssociation in timeAssociations) [timeAssociation snooze]; 230 | 231 | } 232 | 233 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 234 | ┃ Totally destroy the ntp associations .. ┃ 235 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 236 | - (void) finishAssociations { 237 | 238 | for (NetAssociation * timeAssociation in timeAssociations) [timeAssociation finish]; 239 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 240 | } 241 | 242 | #pragma mark - 243 | #pragma mark I n t e r n a l • M e t h o d s 244 | 245 | @end 246 | -------------------------------------------------------------------------------- /ios-ntp-rez/en.lproj/Storyboard.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 44 | 53 | 62 | 71 | 80 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /ntp-test/ntp_test.m: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ ntp_test.m ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Jun04/15 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import 8 | #import "NetAssociation.h" 9 | 10 | @interface ntp_test : XCTestCase 11 | 12 | @end 13 | 14 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 15 | │ Convert from NTP time to Unix time │ 16 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 17 | void ntp2unix(const union ntpTime * ntp, struct timeval * tv) { 18 | tv->tv_sec = ntp->partials.wholeSeconds - JAN_1970; 19 | tv->tv_usec = (uint32_t)((double)ntp->partials.fractSeconds / (1LL<<32) * 1.0e6); 20 | } 21 | 22 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 23 | │ get (ntpTime2 - ntpTime1) in (double) seconds │ 24 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 25 | double ntpDiffSecondsB(union ntpTime * start, union ntpTime * stop) { 26 | return (start->floating - stop->floating) / -4294967296.0; 27 | } 28 | 29 | 30 | 31 | @implementation ntp_test 32 | 33 | - (void)setUp { 34 | [super setUp]; 35 | // Put setup code here. This method is called before the invocation of each test method in the class. 36 | } 37 | 38 | - (void)tearDown { 39 | // Put teardown code here. This method is called after the invocation of each test method in the class. 40 | [super tearDown]; 41 | } 42 | 43 | 44 | 45 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 46 | ┃ TEST CONVERSIONS .. convert unix "zerotime" to ntp(32-bit,32-bit) format and back and compare .. ┃ 47 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 48 | - (void)testConvertA1 { 49 | union ntpTime netStamp = {0, JAN_1970}; // network time for 1 January 1970, GMT 50 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 51 | │ Convert from NTP time to Unix time │ 52 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 53 | struct timeval sysStamp; 54 | ntp2unix(&netStamp, &sysStamp); 55 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 56 | │ Convert from Unix time to NTP time │ 57 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 58 | union ntpTime newStamp = unix2ntp(&sysStamp); 59 | 60 | printf("Start with ntp(32-bit,32-bit) .. convert to unix .. convert back to ntp and compare ..\n"); 61 | printf(" ntp: %08x:%08x (%016llx)\n", 62 | netStamp.partials.wholeSeconds, netStamp.partials.fractSeconds, netStamp.floating); 63 | printf(" ntp->unix: %016lx:%08x\n", sysStamp.tv_sec, sysStamp.tv_usec); 64 | printf(" ntp->unix->ntp: %08x:%08x (%016llx)\n", 65 | newStamp.partials.wholeSeconds, newStamp.partials.fractSeconds, newStamp.floating); 66 | 67 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 68 | printf(" μseconds difference: %+6.3f\n", tDiff * 1000000.0); 69 | 70 | XCTAssert(fabs(tDiff) < 0.000001, @"Pass"); 71 | } 72 | 73 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 74 | ┃ TEST CONVERSIONS .. convert unix "zerotime" to ntp(64-bit) format and back and compare .. ┃ 75 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 76 | - (void)testConvertA2 { 77 | union ntpTime netStamp; 78 | netStamp.floating = JAN_1970 << 32; // network time for 1 January 1970, GMT 79 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 80 | │ Convert from NTP time to Unix time │ 81 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 82 | struct timeval sysStamp; 83 | ntp2unix(&netStamp, &sysStamp); 84 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 85 | │ Convert from Unix time to NTP time │ 86 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 87 | union ntpTime newStamp = unix2ntp(&sysStamp); 88 | 89 | printf("Start with ntp(64-bit) .. convert to unix() .. convert back and compare ..\n"); 90 | printf(" ntp: %08x:%08x (%016llx)\n", 91 | netStamp.partials.wholeSeconds, netStamp.partials.fractSeconds, netStamp.floating); 92 | printf(" ntp->unix: %016lx:%08x\n", sysStamp.tv_sec, sysStamp.tv_usec); 93 | printf(" ntp->unix->ntp: %08x:%08x (%016llx)\n", 94 | newStamp.partials.wholeSeconds, newStamp.partials.fractSeconds, newStamp.floating); 95 | 96 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 97 | printf(" μseconds difference: %+6.3f\n", tDiff * 1000000.0); 98 | 99 | XCTAssert(fabs(tDiff) < 0.000001, @"Pass"); // pass if < 1μS 100 | } 101 | 102 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 103 | ┃ TEST CONVERSIONS .. convert unix "zerotime+nudge" to ntp format and back and compare .. ┃ 104 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 105 | - (void)testConvertB1 { 106 | union ntpTime netStamp = {+0x02000, JAN_1970}; // network time for 1 January 1970, GMT 107 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 108 | │ Convert from NTP time to Unix time │ 109 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 110 | struct timeval sysStamp; 111 | ntp2unix(&netStamp, &sysStamp); 112 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 113 | │ Convert from Unix time to NTP time │ 114 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 115 | union ntpTime newStamp = unix2ntp(&sysStamp); 116 | 117 | printf("Start with ntp() .. convert to unix() .. convert back and compare ..\n"); 118 | printf(" ntp: %08x:%08x (%016llx)\n", 119 | netStamp.partials.wholeSeconds, netStamp.partials.fractSeconds, netStamp.floating); 120 | printf(" ntp->unix: %016lx:%08x\n", sysStamp.tv_sec, sysStamp.tv_usec); 121 | printf(" ntp->unix->ntp: %08x:%08x (%016llx)\n", 122 | newStamp.partials.wholeSeconds, newStamp.partials.fractSeconds, newStamp.floating); 123 | 124 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 125 | printf(" μseconds difference: %+6.3f\n", tDiff * 1000000.0); 126 | 127 | tDiff = ntpDiffSecondsB(&netStamp, &newStamp); 128 | printf(" μseconds difference: %+6.3f\n", tDiff * 1000000.0); 129 | 130 | XCTAssert(fabs(tDiff) < 0.000001, @"Pass"); 131 | } 132 | 133 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 134 | ┃ TEST CONVERSIONS .. convert unix "zerotime-nudge" to ntp format and back and compare .. ┃ 135 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 136 | - (void)testConvertB2 { 137 | union ntpTime netStamp = {-0x02000, JAN_1970}; // network time for 1 January 1970, GMT 138 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 139 | │ Convert from NTP time to Unix time │ 140 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 141 | struct timeval sysStamp; 142 | ntp2unix(&netStamp, &sysStamp); 143 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 144 | │ Convert from Unix time to NTP time │ 145 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 146 | union ntpTime newStamp = unix2ntp(&sysStamp); 147 | 148 | printf("Start with ntp() .. convert to unix() .. convert back and compare ..\n"); 149 | printf(" ntp: %08x:%08x (%016llx)\n", 150 | netStamp.partials.wholeSeconds, netStamp.partials.fractSeconds, netStamp.floating); 151 | printf(" ntp->unix: %016lx:%08x\n", sysStamp.tv_sec, sysStamp.tv_usec); 152 | printf(" ntp->unix->ntp: %08x:%08x (%016llx)\n", 153 | newStamp.partials.wholeSeconds, newStamp.partials.fractSeconds, newStamp.floating); 154 | 155 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 156 | printf(" μseconds difference: %+6.3f\n", tDiff * 1000000.0); 157 | 158 | XCTAssert(fabs(tDiff) < 2.0E-6, @"Pass"); 159 | } 160 | 161 | 162 | 163 | 164 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 165 | ┃ TEST CONVERSIONS .. convert unix "ntp-zerotime" to ntp format and back and compare .. ┃ 166 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 167 | - (void)testConvertC { 168 | union ntpTime netStamp = {0, 0x23aa7e80}; // .. 169 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 170 | │ Convert from NTP time to Unix time │ 171 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 172 | struct timeval sysStamp; 173 | ntp2unix(&netStamp, &sysStamp); 174 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 175 | │ Convert from Unix time to NTP time │ 176 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 177 | union ntpTime newStamp = unix2ntp(&sysStamp); 178 | 179 | printf("Start with ntp() .. convert to unix() .. convert back and compare ..\n"); 180 | printf(" ntp: %08x:%08x (%016llx)\n", 181 | netStamp.partials.wholeSeconds, netStamp.partials.fractSeconds, netStamp.floating); 182 | printf(" ntp->unix: %016lx:%08x\n", sysStamp.tv_sec, sysStamp.tv_usec); 183 | printf(" ntp->unix->ntp: %08x:%08x (%016llx)\n", 184 | newStamp.partials.wholeSeconds, newStamp.partials.fractSeconds, newStamp.floating); 185 | 186 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 187 | printf(" μseconds difference: %+6.3f\n", tDiff * 1000000.0); 188 | 189 | XCTAssert(fabs(tDiff) < 2.0E-6, @"Pass"); 190 | } 191 | 192 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 193 | ┃ TEST CONVERSIONS .. convert unix "ntp-zerotime" to ntp format and back and compare .. ┃ 194 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 195 | - (void)testConvertD { 196 | union ntpTime netStamp = {0, 0xa3aa7e80}; // .. 197 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 198 | │ Convert from NTP time to Unix time │ 199 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 200 | struct timeval sysStamp; 201 | ntp2unix(&netStamp, &sysStamp); 202 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 203 | │ Convert from Unix time to NTP time │ 204 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 205 | union ntpTime newStamp = unix2ntp(&sysStamp); 206 | 207 | printf("Start with ntp() .. convert to unix() .. convert back and compare ..\n"); 208 | printf(" ntp: %08x:%08x (%016llx)\n", 209 | netStamp.partials.wholeSeconds, netStamp.partials.fractSeconds, netStamp.floating); 210 | printf(" ntp->unix: %016lx:%08x\n", sysStamp.tv_sec, sysStamp.tv_usec); 211 | printf(" ntp->unix->ntp: %08x:%08x (%016llx)\n", 212 | newStamp.partials.wholeSeconds, newStamp.partials.fractSeconds, newStamp.floating); 213 | 214 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 215 | printf(" μseconds difference: %+6.3f\n", tDiff * 1000000.0); 216 | 217 | XCTAssert(fabs(tDiff) < 2.0E-6, @"Pass"); 218 | } 219 | 220 | - (void)testConvert5 { 221 | union ntpTime netStamp = {-1, 0x23aa7e80}; 222 | struct timeval sysStamp; 223 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 224 | │ Convert from NTP time to Unix time │ 225 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 226 | ntp2unix(&netStamp, &sysStamp); 227 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 228 | │ Convert from Unix time to NTP time │ 229 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 230 | union ntpTime newStamp = unix2ntp(&sysStamp); 231 | 232 | printf("Start with ntp() .. convert to unix() .. convert back and compare ..\n"); 233 | printf(" ntp: %08x:%08x (%016llx)\n", 234 | netStamp.partials.wholeSeconds, netStamp.partials.fractSeconds, netStamp.floating); 235 | printf(" ntp->unix: %016lx:%08x\n", sysStamp.tv_sec, sysStamp.tv_usec); 236 | printf(" ntp->unix->ntp: %08x:%08x (%016llx)\n", 237 | newStamp.partials.wholeSeconds, newStamp.partials.fractSeconds, newStamp.floating); 238 | 239 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 240 | printf(" μseconds difference: %+6.3f\n", tDiff * 1000000.0); 241 | 242 | XCTAssert(fabs(tDiff) < 2.0E-6, @"Pass"); 243 | } 244 | 245 | - (void)testConvert6 { 246 | union ntpTime netStamp = {-1, 0xa3aa7e80}; 247 | struct timeval sysStamp; 248 | 249 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 250 | │ Convert from NTP time to Unix time │ 251 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 252 | ntp2unix(&netStamp, &sysStamp); 253 | 254 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 255 | │ Convert from Unix time to NTP time │ 256 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 257 | union ntpTime newStamp = unix2ntp(&sysStamp); 258 | 259 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 260 | 261 | printf("%12.10f\n", tDiff); 262 | XCTAssert(fabs(tDiff) < 2.0E-6, @"Pass"); 263 | } 264 | 265 | - (void)testConvert7 { 266 | union ntpTime netStamp = {0x80000000, JAN_1970}; 267 | union ntpTime newStamp = {0, JAN_1970}; 268 | 269 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 270 | 271 | printf("%12.10f\n", tDiff); 272 | XCTAssert(tDiff+0.5 < 2.0E-6, @"Pass"); 273 | } 274 | 275 | - (void)testConvert8 { 276 | union ntpTime netStamp = {0, JAN_1970+1}; 277 | union ntpTime newStamp = {0, JAN_1970}; 278 | 279 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 280 | 281 | printf("%12.10f\n", tDiff); 282 | XCTAssert(tDiff+1.0 < 2.0E-6, @"Pass"); 283 | } 284 | 285 | - (void)testConvert9 { 286 | union ntpTime netStamp = {0, JAN_1970}; 287 | union ntpTime newStamp = {0x80000000, JAN_1970}; 288 | 289 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 290 | 291 | printf("%12.10f\n", tDiff); 292 | XCTAssert(tDiff-0.5 < 2.0E-6, @"Pass"); 293 | } 294 | 295 | - (void)testConvert10 { 296 | union ntpTime netStamp = {0, JAN_1970}; 297 | union ntpTime newStamp = {0, JAN_1970+1}; 298 | 299 | double tDiff = ntpDiffSeconds(&netStamp, &newStamp); 300 | 301 | printf("%12.10f\n", tDiff); 302 | XCTAssert(tDiff-1.0 < 2.0E-6, @"Pass"); 303 | } 304 | 305 | //- (void)testConvert11 { 306 | // struct timeval sysStamp; 307 | // 308 | // gettimeofday(&sysStamp, NULL); 309 | // printf("%08lx:%08x\n", sysStamp.tv_sec, sysStamp.tv_usec); 310 | // XCTAssert(true, @"Pass"); 311 | //} 312 | 313 | - (void)testPerformanceExample { 314 | [self measureBlock:^{ 315 | union ntpTime time = ntp_time_now(); 316 | }]; 317 | } 318 | 319 | @end 320 | -------------------------------------------------------------------------------- /ios-ntp-rez/en.lproj/ntpViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1056 5 | 10H574 6 | 823 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 132 12 | 13 | 14 | YES 15 | 16 | 17 | YES 18 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 19 | 20 | 21 | YES 22 | 23 | YES 24 | 25 | 26 | YES 27 | 28 | 29 | 30 | YES 31 | 32 | IBFilesOwner 33 | IBCocoaTouchFramework 34 | 35 | 36 | IBFirstResponder 37 | IBCocoaTouchFramework 38 | 39 | 40 | 41 | 274 42 | 43 | YES 44 | 45 | 46 | 292 47 | {{20, 20}, {30, 21}} 48 | 49 | NO 50 | YES 51 | 7 52 | NO 53 | IBCocoaTouchFramework 54 | sys: 55 | 56 | Helvetica 57 | 13 58 | 16 59 | 60 | 61 | 1 62 | MCAwIDAAA 63 | 64 | 65 | 3 66 | MQA 67 | 68 | 1 69 | 10 70 | 71 | 72 | 73 | 292 74 | {{58, 20}, {242, 21}} 75 | 76 | NO 77 | YES 78 | 7 79 | NO 80 | IBCocoaTouchFramework 81 | sysClock 82 | 83 | 84 | 85 | 1 86 | 10 87 | 88 | 89 | 90 | 292 91 | {{20, 49}, {30, 21}} 92 | 93 | NO 94 | YES 95 | 7 96 | NO 97 | IBCocoaTouchFramework 98 | net: 99 | 100 | 101 | 102 | 1 103 | 10 104 | 105 | 106 | 107 | 292 108 | {{20, 78}, {30, 21}} 109 | 110 | NO 111 | YES 112 | 7 113 | NO 114 | IBCocoaTouchFramework 115 | dif: 116 | 117 | 118 | 119 | 1 120 | 10 121 | 122 | 123 | 124 | 292 125 | {{58, 49}, {242, 21}} 126 | 127 | NO 128 | YES 129 | 7 130 | NO 131 | IBCocoaTouchFramework 132 | netClock 133 | 134 | 135 | 136 | 1 137 | 10 138 | 139 | 140 | 141 | 292 142 | {{58, 78}, {242, 21}} 143 | 144 | NO 145 | YES 146 | 7 147 | NO 148 | IBCocoaTouchFramework 149 | diffMillis 150 | 151 | 152 | 153 | 1 154 | 10 155 | 156 | 157 | {320, 460} 158 | 159 | 3 160 | MC43NQA 161 | 162 | 2 163 | 164 | 165 | NO 166 | 167 | IBCocoaTouchFramework 168 | 169 | 170 | 171 | 172 | YES 173 | 174 | 175 | view 176 | 177 | 178 | 179 | 16 180 | 181 | 182 | 183 | 184 | YES 185 | 186 | 0 187 | 188 | 189 | 190 | 191 | 192 | -1 193 | 194 | 195 | File's Owner 196 | 197 | 198 | -2 199 | 200 | 201 | 202 | 203 | 6 204 | 205 | 206 | YES 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 8 218 | 219 | 220 | 221 | 222 | 9 223 | 224 | 225 | 226 | 227 | 10 228 | 229 | 230 | 231 | 232 | 11 233 | 234 | 235 | 236 | 237 | 12 238 | 239 | 240 | 241 | 242 | 13 243 | 244 | 245 | 246 | 247 | 248 | 249 | YES 250 | 251 | YES 252 | -1.CustomClassName 253 | -2.CustomClassName 254 | 10.IBPluginDependency 255 | 10.IBViewBoundsToFrameTransform 256 | 11.IBPluginDependency 257 | 11.IBViewBoundsToFrameTransform 258 | 12.IBPluginDependency 259 | 12.IBViewBoundsToFrameTransform 260 | 13.IBPluginDependency 261 | 13.IBViewBoundsToFrameTransform 262 | 6.IBEditorWindowLastContentRect 263 | 6.IBPluginDependency 264 | 8.IBPluginDependency 265 | 8.IBViewBoundsToFrameTransform 266 | 9.IBPluginDependency 267 | 9.IBViewBoundsToFrameTransform 268 | 269 | 270 | YES 271 | ntpAViewController 272 | UIResponder 273 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 274 | 275 | AUGgAABCRAAAA 276 | 277 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 278 | 279 | AUJoAABCRAAAA 280 | 281 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 282 | 283 | P4AAAL+AAABByAAAwpIAAA 284 | 285 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 286 | 287 | P4AAAL+AAABCfAAAwpIAAA 288 | 289 | {{269, 172}, {320, 480}} 290 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 291 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 292 | 293 | AUGgAABBoAAAA 294 | 295 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 296 | 297 | AUJoAABBoAAAA 298 | 299 | 300 | 301 | 302 | YES 303 | 304 | 305 | YES 306 | 307 | 308 | 309 | 310 | YES 311 | 312 | 313 | YES 314 | 315 | 316 | 317 | 16 318 | 319 | 320 | 321 | YES 322 | 323 | NSObject 324 | 325 | IBProjectSource 326 | ../cocoaasyncsocket-read-only/AsyncUdpSocket.h 327 | 328 | 329 | 330 | ntpAViewController 331 | UIViewController 332 | 333 | YES 334 | 335 | YES 336 | difference 337 | netClock 338 | sysClock 339 | 340 | 341 | YES 342 | NSString 343 | NSString 344 | NSString 345 | 346 | 347 | 348 | YES 349 | 350 | YES 351 | difference 352 | netClock 353 | sysClock 354 | 355 | 356 | YES 357 | 358 | difference 359 | NSString 360 | 361 | 362 | netClock 363 | NSString 364 | 365 | 366 | sysClock 367 | NSString 368 | 369 | 370 | 371 | 372 | IBProjectSource 373 | Classes/ntpAViewController.h 374 | 375 | 376 | 377 | 378 | YES 379 | 380 | NSObject 381 | 382 | IBFrameworkSource 383 | Foundation.framework/Headers/NSError.h 384 | 385 | 386 | 387 | NSObject 388 | 389 | IBFrameworkSource 390 | Foundation.framework/Headers/NSFileManager.h 391 | 392 | 393 | 394 | NSObject 395 | 396 | IBFrameworkSource 397 | Foundation.framework/Headers/NSKeyValueCoding.h 398 | 399 | 400 | 401 | NSObject 402 | 403 | IBFrameworkSource 404 | Foundation.framework/Headers/NSKeyValueObserving.h 405 | 406 | 407 | 408 | NSObject 409 | 410 | IBFrameworkSource 411 | Foundation.framework/Headers/NSKeyedArchiver.h 412 | 413 | 414 | 415 | NSObject 416 | 417 | IBFrameworkSource 418 | Foundation.framework/Headers/NSObject.h 419 | 420 | 421 | 422 | NSObject 423 | 424 | IBFrameworkSource 425 | Foundation.framework/Headers/NSRunLoop.h 426 | 427 | 428 | 429 | NSObject 430 | 431 | IBFrameworkSource 432 | Foundation.framework/Headers/NSThread.h 433 | 434 | 435 | 436 | NSObject 437 | 438 | IBFrameworkSource 439 | Foundation.framework/Headers/NSURL.h 440 | 441 | 442 | 443 | NSObject 444 | 445 | IBFrameworkSource 446 | Foundation.framework/Headers/NSURLConnection.h 447 | 448 | 449 | 450 | NSObject 451 | 452 | IBFrameworkSource 453 | UIKit.framework/Headers/UIAccessibility.h 454 | 455 | 456 | 457 | NSObject 458 | 459 | IBFrameworkSource 460 | UIKit.framework/Headers/UINibLoading.h 461 | 462 | 463 | 464 | NSObject 465 | 466 | IBFrameworkSource 467 | UIKit.framework/Headers/UIResponder.h 468 | 469 | 470 | 471 | NSString 472 | 473 | IBFrameworkSource 474 | Foundation.framework/Headers/NSPathUtilities.h 475 | 476 | 477 | 478 | NSString 479 | NSObject 480 | 481 | IBFrameworkSource 482 | Foundation.framework/Headers/NSString.h 483 | 484 | 485 | 486 | NSString 487 | 488 | 489 | 490 | NSString 491 | 492 | IBFrameworkSource 493 | UIKit.framework/Headers/UIStringDrawing.h 494 | 495 | 496 | 497 | UILabel 498 | UIView 499 | 500 | IBFrameworkSource 501 | UIKit.framework/Headers/UILabel.h 502 | 503 | 504 | 505 | UIResponder 506 | NSObject 507 | 508 | 509 | 510 | UISearchBar 511 | UIView 512 | 513 | IBFrameworkSource 514 | UIKit.framework/Headers/UISearchBar.h 515 | 516 | 517 | 518 | UISearchDisplayController 519 | NSObject 520 | 521 | IBFrameworkSource 522 | UIKit.framework/Headers/UISearchDisplayController.h 523 | 524 | 525 | 526 | UIView 527 | 528 | IBFrameworkSource 529 | UIKit.framework/Headers/UIPrintFormatter.h 530 | 531 | 532 | 533 | UIView 534 | 535 | IBFrameworkSource 536 | UIKit.framework/Headers/UITextField.h 537 | 538 | 539 | 540 | UIView 541 | UIResponder 542 | 543 | IBFrameworkSource 544 | UIKit.framework/Headers/UIView.h 545 | 546 | 547 | 548 | UIViewController 549 | 550 | IBFrameworkSource 551 | UIKit.framework/Headers/UINavigationController.h 552 | 553 | 554 | 555 | UIViewController 556 | 557 | IBFrameworkSource 558 | UIKit.framework/Headers/UIPopoverController.h 559 | 560 | 561 | 562 | UIViewController 563 | 564 | IBFrameworkSource 565 | UIKit.framework/Headers/UISplitViewController.h 566 | 567 | 568 | 569 | UIViewController 570 | 571 | IBFrameworkSource 572 | UIKit.framework/Headers/UITabBarController.h 573 | 574 | 575 | 576 | UIViewController 577 | UIResponder 578 | 579 | IBFrameworkSource 580 | UIKit.framework/Headers/UIViewController.h 581 | 582 | 583 | 584 | 585 | 0 586 | IBCocoaTouchFramework 587 | 588 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 589 | 590 | 591 | 592 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 593 | 594 | 595 | YES 596 | ../ntpA.xcodeproj 597 | 3 598 | 132 599 | 600 | 601 | -------------------------------------------------------------------------------- /ios-ntp-lib/NetAssociation.m: -------------------------------------------------------------------------------- 1 | /*╔══════════════════════════════════════════════════════════════════════════════════════════════════╗ 2 | ║ NetAssociation.m ║ 3 | ║ ║ 4 | ║ Created by Gavin Eadie on Nov03/10 ... Copyright 2010-21 Ramsay Consulting. All rights reserved. ║ 5 | ╚══════════════════════════════════════════════════════════════════════════════════════════════════╝*/ 6 | 7 | #import "NetAssociation.h" 8 | #import "ntp-log.h" 9 | 10 | #import 11 | 12 | #pragma - 13 | #pragma mark T i m e • C o n v e r t e r s 14 | 15 | static union ntpTime NTP_1970 = {0, JAN_1970}; // network time for 1 January 1970, GMT 16 | 17 | static double pollIntervals[18] = { 18 | 2.0, 16.0, 16.0, 16.0, 16.0, 35.0, 72.0, 127.0, 258.0, 19 | 511.0, 1024.0, 2048.0, 4096.0, 8192.0, 16384.0, 32768.0, 65536.0, 131072.0 20 | }; 21 | 22 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 23 | │ get current time in NTP format │ 24 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 25 | union ntpTime ntp_time_now() { 26 | struct timeval now; 27 | gettimeofday(&now, (struct timezone *)NULL); 28 | return unix2ntp(&now); 29 | } 30 | 31 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 32 | │ Convert from Unix time to NTP time │ 33 | │ (on MacOSX clock resolution is 1μS, so ntp's ~12 low bits are meaningless) │ 34 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 35 | union ntpTime unix2ntp(const struct timeval * tv) { 36 | union ntpTime ntp1; 37 | 38 | ntp1.partials.wholeSeconds = (uint32_t)(tv->tv_sec + JAN_1970); 39 | ntp1.partials.fractSeconds = (uint32_t)((double)tv->tv_usec * (1LL<<32) * 1.0e-6); 40 | return ntp1; 41 | } 42 | 43 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 44 | │ get (ntpTime2 - ntpTime1) in (double) seconds │ 45 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 46 | double ntpDiffSeconds(union ntpTime * start, union ntpTime * stop) { 47 | int32_t a; 48 | uint32_t b; 49 | a = stop->partials.wholeSeconds - start->partials.wholeSeconds; 50 | if (stop->partials.fractSeconds >= start->partials.fractSeconds) { 51 | b = stop->partials.fractSeconds - start->partials.fractSeconds; 52 | } 53 | else { 54 | b = start->partials.fractSeconds - stop->partials.fractSeconds; 55 | b = ~b; 56 | a -= 1; 57 | } 58 | 59 | return a + b / 4294967296.0; 60 | } 61 | 62 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 63 | ┃ NetAssociation: Private Variables ┃ 64 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 65 | @interface NetAssociation () { 66 | 67 | GCDAsyncUdpSocket * socket; // NetAssociation UDP Socket 68 | 69 | NSTimer * repeatingTimer; // fires off an ntp request ... 70 | int pollingIntervalIndex; // index into polling interval table 71 | 72 | union ntpTime ntpClientSendTime, 73 | ntpServerRecvTime, 74 | ntpServerSendTime, 75 | ntpClientRecvTime, 76 | ntpServerBaseTime; 77 | 78 | int li, vn, mode, stratum, poll, prec, refid; 79 | 80 | double timerWobbleFactor; // 0.75 .. 1.25 81 | 82 | double fifoQueue[8]; 83 | short fifoIndex; 84 | 85 | } 86 | 87 | @property (readonly) double root_delay; // milliSeconds 88 | @property (readonly) double dispersion; // milliSeconds 89 | @property (readonly) double roundtrip; // seconds 90 | 91 | @end 92 | 93 | #pragma mark - 94 | #pragma mark N E T W O R K • A S S O C I A T I O N 95 | 96 | @implementation NetAssociation 97 | 98 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 99 | ┃ Initialize the association with default initial values and a blank socket .. ┃ 100 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 101 | - (instancetype) initWithServerName:(NSString *) serverName { 102 | if (self = [super init]) { 103 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 104 | │ Set initial/default values for instance variables ... │ 105 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 106 | _delegate = self; 107 | pollingIntervalIndex = 0; // ensure the first timer firing is soon 108 | _active = FALSE; // isn't running till it reports time ... 109 | _trusty = FALSE; // don't trust this clock to start with ... 110 | _offset = INFINITY; // start with net clock meaningless 111 | _server = serverName; 112 | 113 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 114 | │ Create a UDP socket that will communicate with the time server and set its delegate ... │ 115 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 116 | socket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self 117 | delegateQueue:dispatch_queue_create( 118 | [serverName cStringUsingEncoding:NSUTF8StringEncoding], DISPATCH_QUEUE_SERIAL)]; 119 | 120 | [self registerObservations]; 121 | } 122 | 123 | NTP_Logging(@"Association•Init: [%@]", serverName); 124 | 125 | return self; 126 | } 127 | 128 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 129 | ┃ This sets the association in a mode where it repeatedly gets time from its server and performs ┃ 130 | ┃ statical check and averages on these multiple values to provide a more accurate time. ┃ 131 | ┃ starts the timer firing (sets the fire time randonly within the next five seconds) ... ┃ 132 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 133 | - (void) enable { 134 | NTP_Logging(@"Association•Enable : [%@]", _server); 135 | 136 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 137 | │ Create a first-in/first-out queue for time samples. As we compute each new time obtained from │ 138 | │ the server we push it into the fifo. We sample the contents of the fifo for quality and, if it │ 139 | │ meets our standards we use the contents of the fifo to obtain a weighted average of the times. │ 140 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 141 | for (short i = 0; i < 8; i++) fifoQueue[i] = NAN; // set fifo to all empty 142 | fifoIndex = 0; 143 | 144 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 145 | │ Finally, initialize the repeating timer that queries the server, set it's trigger time to the │ 146 | │ infinite future, and put it on the run loop .. nothing will happen (yet) │ 147 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 148 | repeatingTimer = [NSTimer timerWithTimeInterval:MAXFLOAT 149 | target:self selector:@selector(queryTimeServer) 150 | userInfo:nil repeats:YES]; 151 | repeatingTimer.tolerance = 1.0; // it can be up to 1 second late 152 | [[NSRunLoop mainRunLoop] addTimer:repeatingTimer forMode:NSDefaultRunLoopMode]; 153 | 154 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 155 | │ now start the timer .. fire the first one soon, and put some wobble in its timing so we don't │ 156 | │ get swarms of activity as all the associations fire at the same time. │ 157 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 158 | timerWobbleFactor = ((float)rand()/(float)RAND_MAX / 2.0) + 0.75; // 0.75 .. 1.25 159 | NSTimeInterval interval = pollIntervals[pollingIntervalIndex] * timerWobbleFactor; 160 | repeatingTimer.tolerance = 5.0; // it can be up to 5 seconds late 161 | repeatingTimer.fireDate = [NSDate dateWithTimeIntervalSinceNow:interval]; 162 | 163 | pollingIntervalIndex = 4; // subsequent timers fire at default intervals 164 | } 165 | 166 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 167 | ┃ Set the receiver and send the time query with 2 second timeout, ... ┃ 168 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 169 | - (void) queryTimeServer { 170 | [self sendTimeQuery]; 171 | 172 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 173 | │ Put some wobble into the repeating time so they don't synchronize and thump the network │ 174 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 175 | timerWobbleFactor = ((float)rand()/(float)RAND_MAX / 2.0) + 0.75; // 0.75 .. 1.25 176 | NSTimeInterval interval = pollIntervals[pollingIntervalIndex] * timerWobbleFactor; 177 | repeatingTimer.fireDate = [NSDate dateWithTimeIntervalSinceNow:interval]; 178 | } 179 | 180 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 181 | ┃ ... ┃ 182 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 183 | - (void) sendTimeQuery { 184 | NSError * error = nil; 185 | 186 | [socket sendData:[self createPacket] toHost:_server port:123 withTimeout:2.0 tag:0]; 187 | 188 | if(![socket beginReceiving:&error]) { 189 | NTP_Logging(@"Unable to start listening on socket for [%@] due to error [%@]", _server, error); 190 | return; 191 | } 192 | } 193 | 194 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 195 | ┃ This stops the timer firing (sets the fire time to the infinite future) ... ┃ 196 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 197 | - (void) snooze { 198 | NTP_Logging(@"Association•Snooze : [%@]", _server); 199 | 200 | repeatingTimer.fireDate = [NSDate distantFuture]; 201 | _active = FALSE; 202 | } 203 | 204 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 205 | ┃ This stops the timer firing (sets the fire time to the infinite future) ... ┃ 206 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 207 | - (void) finish { 208 | NTP_Logging(@"Association•Finish : [%@]", _server); 209 | 210 | [repeatingTimer invalidate]; 211 | 212 | _active = FALSE; 213 | } 214 | 215 | #pragma mark N e t w o r k • T r a n s a c t i o n s 216 | 217 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 218 | │ Create a time query packet ... │ 219 | │──────────────────────────────────────────────────────────────────────────────────────────────────│ 220 | │ │ 221 | │ 1 2 3 │ 222 | │ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 │ 223 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 224 | │ [ 0] | L | Ver |Mode | Stratum | Poll | Precision | │ 225 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 226 | │ [ 1] | Root Delay (32) | in NTP short format │ 227 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 228 | │ [ 2] | Root Dispersion (32) | in NTP short format │ 229 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 230 | │ [ 3] | Reference Identifier | │ 231 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 232 | │ [ 4] | | │ 233 | │ | Reference Timestamp (64) | in NTP long format │ 234 | │ [ 5] | | │ 235 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 236 | │ [ 6] | | │ 237 | │ | Originate Timestamp (64) | in NTP long format │ 238 | │ [ 7] | | │ 239 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 240 | │ [ 8] | | │ 241 | │ | Receive Timestamp (64) | in NTP long format │ 242 | │ [ 9] | | │ 243 | │ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ 244 | │ [10] | | │ 245 | │ | Transmit Timestamp (64) | in NTP long format │ 246 | │ [11] | | │ 247 | │ │ 248 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 249 | 250 | - (NSData *) createPacket { 251 | uint32_t wireData[12]; 252 | 253 | memset(wireData, 0, sizeof wireData); 254 | wireData[0] = htonl((0 << 30) | // no Leap Indicator 255 | (4 << 27) | // NTP v4 256 | (3 << 24) | // mode = client sending 257 | (0 << 16) | // stratum (n/a) 258 | (4 << 8) | // polling rate (16 secs) 259 | (-6 & 0xff)); // precision (~15 mSecs) 260 | wireData[1] = htonl(1<<16); 261 | wireData[2] = htonl(1<<16); 262 | 263 | ntpClientSendTime = ntp_time_now(); 264 | 265 | wireData[10] = htonl(ntpClientSendTime.partials.wholeSeconds); // Transmit Timestamp 266 | wireData[11] = htonl(ntpClientSendTime.partials.fractSeconds); 267 | 268 | return [NSData dataWithBytes:wireData length:48]; 269 | } 270 | 271 | - (void) decodePacket:(NSData *) data { 272 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 273 | │ grab the packet arrival time as fast as possible, before computations below ... │ 274 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 275 | ntpClientRecvTime = ntp_time_now(); 276 | 277 | uint32_t wireData[12]; 278 | [data getBytes:wireData length:48]; 279 | 280 | li = ntohl(wireData[0]) >> 30 & 0x03; 281 | vn = ntohl(wireData[0]) >> 27 & 0x07; 282 | mode = ntohl(wireData[0]) >> 24 & 0x07; 283 | stratum = ntohl(wireData[0]) >> 16 & 0xff; 284 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 285 | │ Poll: 8-bit signed integer representing the maximum interval between successive messages, │ 286 | │ in log2 seconds. Suggested default limits for minimum and maximum poll intervals are 6 and 10. │ 287 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 288 | poll = ntohl(wireData[0]) >> 8 & 0xff; 289 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 290 | │ Precision: 8-bit signed integer representing the precision of the system clock, in log2 seconds.│ 291 | │ (-10 corresponds to about 1 millisecond, -20 to about 1 microSecond) │ 292 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 293 | prec = ntohl(wireData[0]) & 0xff; 294 | if (prec & 0x80) prec |= 0xffffff00; // -ve byte --> -ve int 295 | 296 | _root_delay = ntohl(wireData[1]) * 0.0152587890625; // delay (mS) [1000.0/2**16]. 297 | _dispersion = ntohl(wireData[2]) * 0.0152587890625; // error (mS) 298 | 299 | refid = ntohl(wireData[3]); 300 | 301 | ntpServerBaseTime.partials.wholeSeconds = ntohl(wireData[4]); // when server clock was wound 302 | ntpServerBaseTime.partials.fractSeconds = ntohl(wireData[5]); 303 | 304 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 305 | │ if the send time in the packet isn't the same as the remembered send time, ditch it ... │ 306 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 307 | if (ntpClientSendTime.partials.wholeSeconds != ntohl(wireData[6]) || 308 | ntpClientSendTime.partials.fractSeconds != ntohl(wireData[7])) return; // NO; 309 | 310 | ntpServerRecvTime.partials.wholeSeconds = ntohl(wireData[8]); 311 | ntpServerRecvTime.partials.fractSeconds = ntohl(wireData[9]); 312 | ntpServerSendTime.partials.wholeSeconds = ntohl(wireData[10]); 313 | ntpServerSendTime.partials.fractSeconds = ntohl(wireData[11]); 314 | 315 | // NTP_Logging(@"%@", [self prettyPrintPacket]); 316 | 317 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 318 | │ determine the quality of this particular time .. │ 319 | │ .. if max_error is less than 50mS (and not zero) AND │ 320 | │ .. stratum > 0 AND │ 321 | │ .. the mode is 4 (packet came from server) AND │ 322 | │ .. the server clock was set less than 1 minute ago │ 323 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 324 | _offset = INFINITY; // clock meaningless 325 | if ((_dispersion < 100.0) && 326 | (stratum > 0) && 327 | (mode == 4) && 328 | (ntpDiffSeconds(&ntpServerBaseTime, &ntpServerSendTime) < 3600.0)) { 329 | 330 | double t41 = ntpDiffSeconds(&ntpClientSendTime, &ntpClientRecvTime); // .. (T4-T1) 331 | double t32 = ntpDiffSeconds(&ntpServerRecvTime, &ntpServerSendTime); // .. (T3-T2) 332 | 333 | _roundtrip = t41 - t32; 334 | 335 | double t21 = ntpDiffSeconds(&ntpServerSendTime, &ntpClientRecvTime); // .. (T2-T1) 336 | double t34 = ntpDiffSeconds(&ntpServerRecvTime, &ntpClientSendTime); // .. (T3-T4) 337 | 338 | _offset = (t21 + t34) / 2.0; // calculate offset 339 | 340 | // NSLog(@"t21=%.6f t34=%.6f delta=%.6f offset=%.6f", t21, t34, _roundtrip, _offset); 341 | _active = TRUE; 342 | 343 | // NTP_Logging(@"%@", [self prettyPrintTimers]); 344 | } 345 | else { 346 | NTP_Logging(@" [%@] : bad data .. %7.1f", _server, ntpDiffSeconds(&ntpServerBaseTime, &ntpServerSendTime)); 347 | } 348 | 349 | dispatch_async(dispatch_get_main_queue(), ^{ [self->_delegate reportFromDelegate]; });// tell delegate we're done 350 | } 351 | 352 | - (void) reportFromDelegate { 353 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 354 | │ the packet is trustworthy -- compute and store offset in 8-slot fifo ... │ 355 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 356 | 357 | fifoQueue[fifoIndex++ % 8] = _offset; // store offset in seconds 358 | fifoIndex %= 8; // rotate index in range 359 | 360 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 361 | │ look at the (up to eight) offsets in the fifo and and count 'good', 'fail' and 'not used yet' │ 362 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 363 | short good = 0, fail = 0, none = 0; 364 | _offset = 0.0; // reset for averaging 365 | 366 | for (short i = 0; i < 8; i++) { 367 | if (isnan(fifoQueue[i])) { // fifo slot is unused 368 | none++; 369 | continue; 370 | } 371 | if (isinf(fifoQueue[i]) || fabs(fifoQueue[i]) < 0.0001) { // server can't be trusted 372 | fail++; 373 | continue; 374 | } 375 | 376 | good++; 377 | _offset += fifoQueue[i]; // accumulate good times 378 | } 379 | 380 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 381 | │ .. if we have at least one 'good' server response or four or more 'fail' responses, we'll │ 382 | │ inform our management accordingly. If we have less than four 'fails' we won't make any │ 383 | │ note of that ... we won't condemn a server until we get four 'fail' packets. │ 384 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 385 | double stdDev = 0.0; 386 | if (good > 0 || fail > 3) { 387 | _offset = _offset / good; // average good times 388 | 389 | for (short i = 0; i < 8; i++) { 390 | if (isnan(fifoQueue[i])) continue; 391 | 392 | if (isinf(fifoQueue[i]) || fabs(fifoQueue[i]) < 0.001) continue; 393 | 394 | stdDev += (fifoQueue[i] - _offset) * (fifoQueue[i] - _offset); 395 | } 396 | stdDev = sqrt(stdDev/(float)good); 397 | 398 | _trusty = (good+none > 4) && // four or more 'fails' 399 | (fabs(_offset) < .050 || // s.d. < 50 mSec 400 | (fabs(_offset) > 2.0 * stdDev)); // s.d. < offset * 2 401 | 402 | NTP_Logging(@" [%@] {%3.1f,%3.1f,%3.1f,%3.1f,%3.1f,%3.1f,%3.1f,%3.1f} ↑=%i, ↓=%i, %3.1f(%3.1f) %@", _server, 403 | fifoQueue[0]*1000.0, fifoQueue[1]*1000.0, fifoQueue[2]*1000.0, fifoQueue[3]*1000.0, 404 | fifoQueue[4]*1000.0, fifoQueue[5]*1000.0, fifoQueue[6]*1000.0, fifoQueue[7]*1000.0, 405 | good, fail, _offset*1000.0, stdDev*1000.0, _trusty ? @"↑" : @"↓"); 406 | } 407 | 408 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 409 | │ .. if the association is providing times which don't vary much, we could increase its polling │ 410 | │ interval. In practice, once things settle down, the standard deviation on any time server │ 411 | │ seems to fall in the 70-120mS range (plenty close for our work). We usually pick up a few │ 412 | │ stratum=1 servers, it would be a Good Thing to not hammer those so hard ... │ 413 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 414 | if ((stratum == 1 && pollingIntervalIndex != 6) || 415 | (stratum == 2 && pollingIntervalIndex != 5)) { 416 | pollingIntervalIndex = 7 - stratum; 417 | } 418 | } 419 | 420 | #pragma mark N e t w o r k • C a l l b a c k s 421 | 422 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 423 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 424 | - (void) udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag { 425 | } 426 | 427 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 428 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 429 | - (void) udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error { 430 | NTP_Logging(@"didNotSendDataWithTag - %@", error.description); 431 | } 432 | 433 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 434 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 435 | - (void) udpSocket:(GCDAsyncUdpSocket *)sock 436 | didReceiveData:(NSData *)data 437 | fromAddress:(NSData *)address 438 | withFilterContext:(id)filterContext { 439 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 440 | │ grab the packet arrival time as fast as possible, before computations below ... │ 441 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 442 | ntpClientRecvTime = ntp_time_now(); 443 | 444 | [self decodePacket:data]; 445 | 446 | } 447 | 448 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 449 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 450 | - (void) udpSocketDidClose:(GCDAsyncUdpSocket *)sock 451 | withError:(NSError *)error { 452 | NTP_Logging(@"Socket closed : [%@]", _server); 453 | } 454 | 455 | #pragma mark U t i l i t i e s 456 | 457 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 458 | ┃ Make an NSDate from ntpTimestamp ... (via seconds from JAN_1970) ... ┃ 459 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 460 | - (NSDate *) dateFromNetworkTime:(union ntpTime *) networkTime { 461 | return [NSDate dateWithTimeIntervalSince1970:ntpDiffSeconds(&NTP_1970, networkTime)]; 462 | } 463 | 464 | + (NSString *) ipAddrFromName: (NSString *) domainName { 465 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 466 | │ ... resolve the IP address of the named host : "time.vendor.org" --> [123.45.67.89], ... │ 467 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 468 | CFHostRef ntpHostName = CFHostCreateWithName (nil, (__bridge CFStringRef)domainName); 469 | if (nil == ntpHostName) { 470 | NTP_Logging(@"CFHostCreateWithName for %@", domainName); 471 | return NULL; // couldn't create 'host object' ... 472 | } 473 | 474 | CFStreamError nameError; 475 | if (!CFHostStartInfoResolution (ntpHostName, kCFHostAddresses, &nameError)) { 476 | NTP_Logging(@"CFHostStartInfoResolution error %i for %@", (int)nameError.error, domainName); 477 | CFRelease(ntpHostName); 478 | return NULL; // couldn't start resolution ... 479 | } 480 | 481 | Boolean nameFound; 482 | NSArray * ntpHostAddrs = (__bridge NSArray *)(CFHostGetAddressing (ntpHostName, &nameFound)); 483 | 484 | if (!nameFound) { 485 | NTP_Logging(@"CFHostGetAddressing: %@ NOT resolved", ntpHostName); 486 | CFRelease(ntpHostName); 487 | return NULL; // resolution failed ... 488 | } 489 | 490 | if (ntpHostAddrs == nil || ntpHostAddrs.count == 0) { 491 | NTP_Logging(@"CFHostGetAddressing: no addresses resolved for %@", ntpHostName); 492 | CFRelease(ntpHostName); 493 | return NULL; // NO addresses were resolved ... 494 | } 495 | CFRelease(ntpHostName); 496 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 497 | │ for each (sockaddr structure wrapped by a CFDataRef/NSData *) associated with the hostname, │ 498 | │ drop the IP address string into a Set to remove duplicates. │ 499 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 500 | return [GCDAsyncUdpSocket hostFromAddress:ntpHostAddrs[0]]; 501 | } 502 | 503 | #pragma mark P r e t t y P r i n t e r s 504 | 505 | - (NSString *) prettyPrintPacket { 506 | NSMutableString * prettyString = [NSMutableString stringWithFormat:@"prettyPrintPacket [%@]\n\n", _server]; 507 | 508 | [prettyString appendFormat:@" leap indicator: %3d\n version number: %3d\n" 509 | " protocol mode: %3d\n stratum: %3d\n" 510 | " poll interval: %3d\n" 511 | " precision exp: %3d\n\n", li, vn, mode, stratum, poll, prec]; 512 | 513 | [prettyString appendFormat:@" root delay: %7.3f (mS)\n" 514 | " dispersion: %7.3f (mS)\n\n", _root_delay, _dispersion]; 515 | 516 | [prettyString appendFormat:@"client send time: %010u.%06d (%@)\n", 517 | ntpClientSendTime.partials.wholeSeconds, 518 | (uint32_t)((double)ntpClientSendTime.partials.fractSeconds / (1LL<<32) * 1.0e6), 519 | [self dateFromNetworkTime:&ntpClientSendTime]]; 520 | 521 | [prettyString appendFormat:@"server recv time: %010u.%06d (%@)\n", 522 | ntpServerRecvTime.partials.wholeSeconds, 523 | (uint32_t)((double)ntpServerRecvTime.partials.fractSeconds / (1LL<<32) * 1.0e6), 524 | [self dateFromNetworkTime:&ntpServerRecvTime]]; 525 | 526 | [prettyString appendFormat:@"server send time: %010u.%06d (%@)\n", 527 | ntpServerSendTime.partials.wholeSeconds, 528 | (uint32_t)((double)ntpServerSendTime.partials.fractSeconds / (1LL<<32) * 1.0e6), 529 | [self dateFromNetworkTime:&ntpServerSendTime]]; 530 | 531 | [prettyString appendFormat:@"client recv time: %010u.%06d (%@)\n\n", 532 | ntpClientRecvTime.partials.wholeSeconds, 533 | (uint32_t)((double)ntpClientRecvTime.partials.fractSeconds / (1LL<<32) * 1.0e6), 534 | [self dateFromNetworkTime:&ntpClientRecvTime]]; 535 | 536 | [prettyString appendFormat:@"server clock set: %010u.%06d (%@)\n\n", 537 | ntpServerBaseTime.partials.wholeSeconds, 538 | (uint32_t)((double)ntpServerBaseTime.partials.fractSeconds / (1LL<<32) * 1.0e6), 539 | [self dateFromNetworkTime:&ntpServerBaseTime]]; 540 | 541 | return prettyString; 542 | } 543 | 544 | - (NSString *) prettyPrintTimers { 545 | NSMutableString * prettyString = [NSMutableString stringWithFormat:@"prettyPrintTimers\n\n"]; 546 | 547 | [prettyString appendFormat:@"time server addr: [%@]\n" 548 | " round trip time: %7.3f (mS)\n" 549 | " clock offset: %7.3f (mS)\n\n", 550 | _server, _roundtrip * 1000.0, _offset * 1000.0]; 551 | 552 | return prettyString; 553 | } 554 | 555 | - (NSString *) description { 556 | return [NSString stringWithFormat:@"%@ [%@] stratum=%i; offset=%3.1f±%3.1fmS", 557 | _trusty ? @"↑" : @"↓", _server, stratum, _offset, _dispersion]; 558 | } 559 | 560 | #pragma mark N o t i f i c a t i o n • T r a p s 561 | 562 | - (void)registerObservations { 563 | 564 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 565 | ┃ if associations are going to have a life, they have to react to their app being backgrounded. ┃ 566 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 567 | 568 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 569 | │ applicationBack -- catch the notification when the application goes into the background │ 570 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 571 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification 572 | object:nil queue:nil 573 | usingBlock:^ 574 | (NSNotification * note) { 575 | NTP_Logging(@"Application -> Background"); 576 | [self snooze]; 577 | }]; 578 | 579 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 580 | │ applicationFore -- catch the notification when the application comes out of the background │ 581 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 582 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification 583 | object:nil queue:nil 584 | usingBlock:^ 585 | (NSNotification * note) { 586 | NTP_Logging(@"Application -> Foreground"); 587 | [self enable]; 588 | }]; 589 | 590 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 591 | │ applicationQuit -- catch the notification when the application comes out of the background │ 592 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 593 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification 594 | object:nil queue:nil 595 | usingBlock:^ (NSNotification * note) { 596 | NTP_Logging(@"Application -> Terminate"); 597 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 598 | [self finish]; 599 | }]; 600 | 601 | /*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 602 | ┃ if associations are going to have a life, they have to react to midnight and daylight saving. ┃ 603 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛*/ 604 | 605 | /*┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ 606 | │ significantTimeChange -- trash the fifo .. │ 607 | └──────────────────────────────────────────────────────────────────────────────────────────────────┘*/ 608 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationSignificantTimeChangeNotification 609 | object:nil queue:nil 610 | usingBlock:^ 611 | (NSNotification * note) { 612 | NTP_Logging(@"Application -> SignificantTimeChange"); 613 | for (short i = 0; i < 8; i++) self->fifoQueue[i] = NAN; // set fifo to all empty 614 | self->fifoIndex = 0; 615 | }]; 616 | } 617 | 618 | @end 619 | -------------------------------------------------------------------------------- /ios-ntp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 130140C620C5A0F4003D167F /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 130140C520C5A0F4003D167F /* Default-568h@2x.png */; }; 11 | 8602E8321A1D5517001C265E /* ntpAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8602E82F1A1D5517001C265E /* ntpAppDelegate.m */; }; 12 | 86273CCB1A1AACBB00487A18 /* NSDate+NetworkClock.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B2BA4113D9C06100C9385A /* NSDate+NetworkClock.m */; }; 13 | 863555311E09976D00FB8E18 /* ntp.hosts in Resources */ = {isa = PBXBuildFile; fileRef = 866ED2FE1B601121004E4394 /* ntp.hosts */; }; 14 | 865E53A01B20B3EF0048F8B1 /* ntp_test.m in Sources */ = {isa = PBXBuildFile; fileRef = 865E539F1B20B3EF0048F8B1 /* ntp_test.m */; }; 15 | 8661906F126C0CD70046A2B8 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8661906E126C0CD70046A2B8 /* UIKit.framework */; }; 16 | 8661907B126C0CEC0046A2B8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8661907A126C0CEC0046A2B8 /* Foundation.framework */; }; 17 | 86619082126C0CFD0046A2B8 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 86619081126C0CFD0046A2B8 /* CoreGraphics.framework */; }; 18 | 86619086126C0D120046A2B8 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 86619085126C0D120046A2B8 /* CFNetwork.framework */; }; 19 | 866F2B751A1D35DE008CCF83 /* ios-ntp.h in Headers */ = {isa = PBXBuildFile; fileRef = D9B2BA3213D9B6CF00C9385A /* ios-ntp.h */; settings = {ATTRIBUTES = (Public, ); }; }; 20 | 866F2B771A1D3624008CCF83 /* NSDate+NetworkClock.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B2BA4113D9C06100C9385A /* NSDate+NetworkClock.m */; }; 21 | 866F2B781A1D3624008CCF83 /* NetAssociation.m in Sources */ = {isa = PBXBuildFile; fileRef = D91E95DA13D9AF8C004E4194 /* NetAssociation.m */; }; 22 | 866F2B791A1D3624008CCF83 /* NetworkClock.m in Sources */ = {isa = PBXBuildFile; fileRef = D91E95DC13D9AF8C004E4194 /* NetworkClock.m */; }; 23 | 86734BD71A2181FD00F191CE /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 86734BD51A2181FD00F191CE /* Storyboard.storyboard */; }; 24 | 869A37D4259E31B8007C0DE2 /* GCDAsyncUdpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 869A37D2259E31B8007C0DE2 /* GCDAsyncUdpSocket.m */; }; 25 | 869A37D5259E31B8007C0DE2 /* GCDAsyncUdpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 869A37D2259E31B8007C0DE2 /* GCDAsyncUdpSocket.m */; }; 26 | 869A37D6259E31B8007C0DE2 /* GCDAsyncUdpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 869A37D2259E31B8007C0DE2 /* GCDAsyncUdpSocket.m */; }; 27 | 869A37D7259E31B8007C0DE2 /* GCDAsyncUdpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 869A37D2259E31B8007C0DE2 /* GCDAsyncUdpSocket.m */; }; 28 | 869A7CDB1A1AB0AC00067303 /* NetAssociation.m in Sources */ = {isa = PBXBuildFile; fileRef = D91E95DA13D9AF8C004E4194 /* NetAssociation.m */; }; 29 | 869A7CDC1A1AB0AC00067303 /* NetworkClock.m in Sources */ = {isa = PBXBuildFile; fileRef = D91E95DC13D9AF8C004E4194 /* NetworkClock.m */; }; 30 | 86C2B3F71A1DAA1900481E2E /* NSDate+NetworkClock.h in Headers */ = {isa = PBXBuildFile; fileRef = D9B2BA4013D9C06100C9385A /* NSDate+NetworkClock.h */; settings = {ATTRIBUTES = (Public, ); }; }; 31 | 86C2B3F81A1DAA1900481E2E /* NetAssociation.h in Headers */ = {isa = PBXBuildFile; fileRef = D91E95D913D9AF8C004E4194 /* NetAssociation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 32 | 86C2B3F91A1DAA1900481E2E /* NetworkClock.h in Headers */ = {isa = PBXBuildFile; fileRef = D91E95DB13D9AF8C004E4194 /* NetworkClock.h */; settings = {ATTRIBUTES = (Public, ); }; }; 33 | 86CE9ED71A2841FB00AFDE79 /* ntpViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 86CE9ED61A2841FB00AFDE79 /* ntpViewController.m */; }; 34 | 86F300C61A1481C00078CBF9 /* NetAssociation.m in Sources */ = {isa = PBXBuildFile; fileRef = D91E95DA13D9AF8C004E4194 /* NetAssociation.m */; }; 35 | 86F300C81A1481C00078CBF9 /* NetworkClock.m in Sources */ = {isa = PBXBuildFile; fileRef = D91E95DC13D9AF8C004E4194 /* NetworkClock.m */; }; 36 | 86F300CC1A1483900078CBF9 /* NSDate+NetworkClock.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B2BA4113D9C06100C9385A /* NSDate+NetworkClock.m */; }; 37 | D91E95E513D9AF8C004E4194 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D91E95DE13D9AF8C004E4194 /* main.m */; }; 38 | D91E95FF13D9B063004E4194 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D91E95F913D9B063004E4194 /* InfoPlist.strings */; }; 39 | /* End PBXBuildFile section */ 40 | 41 | /* Begin PBXCopyFilesBuildPhase section */ 42 | 866F2B711A1D35A0008CCF83 /* Embed Frameworks */ = { 43 | isa = PBXCopyFilesBuildPhase; 44 | buildActionMask = 2147483647; 45 | dstPath = ""; 46 | dstSubfolderSpec = 10; 47 | files = ( 48 | ); 49 | name = "Embed Frameworks"; 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | 86F300AC1A14815C0078CBF9 /* CopyFiles */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = "include/$(PRODUCT_NAME)"; 56 | dstSubfolderSpec = 16; 57 | files = ( 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXCopyFilesBuildPhase section */ 62 | 63 | /* Begin PBXFileReference section */ 64 | 068C40DC398F9AD4AAAFE3D5 /* Pods-ios_fwk.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ios_fwk.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ios_fwk/Pods-ios_fwk.debug.xcconfig"; sourceTree = ""; }; 65 | 130140C520C5A0F4003D167F /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 66 | 13889D35CCF867F7048E444B /* Pods-ntp-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ntp-app.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ntp-app/Pods-ntp-app.debug.xcconfig"; sourceTree = ""; }; 67 | 460FC93E8F7E2C8B724597B1 /* Pods-ios_fwk.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ios_fwk.release.xcconfig"; path = "Pods/Target Support Files/Pods-ios_fwk/Pods-ios_fwk.release.xcconfig"; sourceTree = ""; }; 68 | 6327AF9F37F7C9F740A08306 /* Pods-ios-lib.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ios-lib.release.xcconfig"; path = "Pods/Target Support Files/Pods-ios-lib/Pods-ios-lib.release.xcconfig"; sourceTree = ""; }; 69 | 70F61A313E882D3E270D6406 /* Pods-ntp-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ntp-app.release.xcconfig"; path = "Pods/Target Support Files/Pods-ntp-app/Pods-ntp-app.release.xcconfig"; sourceTree = ""; }; 70 | 79CEE3E86E11635ED8F18631 /* libPods-ios_fwk.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ios_fwk.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 71 | 8602E82E1A1D5517001C265E /* ntpAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ntpAppDelegate.h; sourceTree = ""; }; 72 | 8602E82F1A1D5517001C265E /* ntpAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ntpAppDelegate.m; sourceTree = ""; }; 73 | 860E46A21A4F7B9E004C705B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 74 | 862DA2551A999FC000F65F3E /* Notes */ = {isa = PBXFileReference; lastKnownFileType = text; name = Notes; path = "ios-ntp-lib/Notes"; sourceTree = ""; }; 75 | 863555321E09CA8100FB8E18 /* draft-ietf-ntp-bcp-02.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "draft-ietf-ntp-bcp-02.pdf"; sourceTree = ""; }; 76 | 865E539B1B20B3EF0048F8B1 /* ntp-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ntp-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 77 | 865E539E1B20B3EF0048F8B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 78 | 865E539F1B20B3EF0048F8B1 /* ntp_test.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ntp_test.m; sourceTree = ""; }; 79 | 8661906E126C0CD70046A2B8 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 80 | 8661907A126C0CEC0046A2B8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 81 | 86619081126C0CFD0046A2B8 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 82 | 86619085126C0D120046A2B8 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 83 | 866ED2FE1B601121004E4394 /* ntp.hosts */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ntp.hosts; sourceTree = ""; }; 84 | 866F2B551A1D35A0008CCF83 /* ios_fwk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ios_fwk.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | 86734BD61A2181FD00F191CE /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = Storyboard.storyboard; sourceTree = ""; }; 86 | 867541861ACA2CD900D9990D /* ios-ntp.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = "ios-ntp.podspec"; sourceTree = ""; }; 87 | 869A37D2259E31B8007C0DE2 /* GCDAsyncUdpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GCDAsyncUdpSocket.m; path = Pods/CocoaAsyncSocket/Source/GCD/GCDAsyncUdpSocket.m; sourceTree = SOURCE_ROOT; }; 88 | 869A37D3259E31B8007C0DE2 /* GCDAsyncUdpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GCDAsyncUdpSocket.h; path = Pods/CocoaAsyncSocket/Source/GCD/GCDAsyncUdpSocket.h; sourceTree = SOURCE_ROOT; }; 89 | 86C2B3F51A1DA95300481E2E /* rfc5905.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = rfc5905.pdf; sourceTree = ""; }; 90 | 86C39F0D126A1FA100A9DCD1 /* ntp-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ntp-app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 91 | 86C79ED71A1D659F00FC7CC2 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 92 | 86C79ED81A1D659F00FC7CC2 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 93 | 86CE9ED51A2841FB00AFDE79 /* ntpViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ntpViewController.h; sourceTree = ""; }; 94 | 86CE9ED61A2841FB00AFDE79 /* ntpViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ntpViewController.m; sourceTree = ""; }; 95 | 86F300AE1A14815C0078CBF9 /* libios-lib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libios-lib.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 96 | C3914825A3B7B959A6C58FB6 /* libPods-ntp-app.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ntp-app.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | C9351D630EE6593D82FB2588 /* Pods-ios-lib.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ios-lib.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ios-lib/Pods-ios-lib.debug.xcconfig"; sourceTree = ""; }; 98 | D91E95D913D9AF8C004E4194 /* NetAssociation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetAssociation.h; sourceTree = ""; }; 99 | D91E95DA13D9AF8C004E4194 /* NetAssociation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetAssociation.m; sourceTree = ""; }; 100 | D91E95DB13D9AF8C004E4194 /* NetworkClock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkClock.h; sourceTree = ""; }; 101 | D91E95DC13D9AF8C004E4194 /* NetworkClock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetworkClock.m; sourceTree = ""; }; 102 | D91E95DE13D9AF8C004E4194 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 103 | D91E95F013D9B018004E4194 /* ntp-app-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "ntp-app-Info.plist"; path = "../ios-ntp-rez/ntp-app-Info.plist"; sourceTree = ""; }; 104 | D91E95FA13D9B063004E4194 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = InfoPlist.strings; sourceTree = ""; }; 105 | D9B2BA2B13D9B50200C9385A /* ios-ntp-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ios-ntp-Info.plist"; sourceTree = ""; }; 106 | D9B2BA2C13D9B50200C9385A /* ntp-log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ntp-log.h"; sourceTree = ""; }; 107 | D9B2BA3213D9B6CF00C9385A /* ios-ntp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ios-ntp.h"; sourceTree = ""; }; 108 | D9B2BA3F13D9B95100C9385A /* ios-ntp.tar.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; name = "ios-ntp.tar.gz"; path = "release/ios-ntp.tar.gz"; sourceTree = ""; }; 109 | D9B2BA4013D9C06100C9385A /* NSDate+NetworkClock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+NetworkClock.h"; sourceTree = ""; }; 110 | D9B2BA4113D9C06100C9385A /* NSDate+NetworkClock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+NetworkClock.m"; sourceTree = ""; }; 111 | F53705249F4662D8943131E8 /* libPods-ios-lib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ios-lib.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 112 | /* End PBXFileReference section */ 113 | 114 | /* Begin PBXFrameworksBuildPhase section */ 115 | 865E53981B20B3EF0048F8B1 /* Frameworks */ = { 116 | isa = PBXFrameworksBuildPhase; 117 | buildActionMask = 2147483647; 118 | files = ( 119 | ); 120 | runOnlyForDeploymentPostprocessing = 0; 121 | }; 122 | 866F2B511A1D35A0008CCF83 /* Frameworks */ = { 123 | isa = PBXFrameworksBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | ); 127 | runOnlyForDeploymentPostprocessing = 0; 128 | }; 129 | 86C39F0A126A1FA100A9DCD1 /* Frameworks */ = { 130 | isa = PBXFrameworksBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | 8661906F126C0CD70046A2B8 /* UIKit.framework in Frameworks */, 134 | 8661907B126C0CEC0046A2B8 /* Foundation.framework in Frameworks */, 135 | 86619082126C0CFD0046A2B8 /* CoreGraphics.framework in Frameworks */, 136 | 86619086126C0D120046A2B8 /* CFNetwork.framework in Frameworks */, 137 | ); 138 | runOnlyForDeploymentPostprocessing = 0; 139 | }; 140 | 86F300AB1A14815C0078CBF9 /* Frameworks */ = { 141 | isa = PBXFrameworksBuildPhase; 142 | buildActionMask = 2147483647; 143 | files = ( 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXFrameworksBuildPhase section */ 148 | 149 | /* Begin PBXGroup section */ 150 | 0746B65C32DF09349E67B6BC /* Pods */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | C9351D630EE6593D82FB2588 /* Pods-ios-lib.debug.xcconfig */, 154 | 6327AF9F37F7C9F740A08306 /* Pods-ios-lib.release.xcconfig */, 155 | 068C40DC398F9AD4AAAFE3D5 /* Pods-ios_fwk.debug.xcconfig */, 156 | 460FC93E8F7E2C8B724597B1 /* Pods-ios_fwk.release.xcconfig */, 157 | 13889D35CCF867F7048E444B /* Pods-ntp-app.debug.xcconfig */, 158 | 70F61A313E882D3E270D6406 /* Pods-ntp-app.release.xcconfig */, 159 | ); 160 | name = Pods; 161 | sourceTree = ""; 162 | }; 163 | 860E46A01A4F7B9E004C705B /* ios-ntp.framework */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 860E46A11A4F7B9E004C705B /* Supporting Files */, 167 | ); 168 | path = "ios-ntp.framework"; 169 | sourceTree = ""; 170 | }; 171 | 860E46A11A4F7B9E004C705B /* Supporting Files */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | 860E46A21A4F7B9E004C705B /* Info.plist */, 175 | ); 176 | name = "Supporting Files"; 177 | sourceTree = ""; 178 | }; 179 | 865E539C1B20B3EF0048F8B1 /* ntp-test */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 865E539F1B20B3EF0048F8B1 /* ntp_test.m */, 183 | 865E539D1B20B3EF0048F8B1 /* Supporting Files */, 184 | ); 185 | path = "ntp-test"; 186 | sourceTree = ""; 187 | }; 188 | 865E539D1B20B3EF0048F8B1 /* Supporting Files */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 865E539E1B20B3EF0048F8B1 /* Info.plist */, 192 | ); 193 | name = "Supporting Files"; 194 | sourceTree = ""; 195 | }; 196 | 86C39EFE126A1FA000A9DCD1 = { 197 | isa = PBXGroup; 198 | children = ( 199 | 130140C520C5A0F4003D167F /* Default-568h@2x.png */, 200 | 86C79ED61A1D657F00FC7CC2 /* ios-ntp-doc */, 201 | D91E95D813D9AF8C004E4194 /* ios-ntp-lib */, 202 | D91E95E813D9B018004E4194 /* ios-ntp-rez */, 203 | D91E95DD13D9AF8C004E4194 /* ios-ntp-app */, 204 | 865E539C1B20B3EF0048F8B1 /* ntp-test */, 205 | 86C39F08126A1FA100A9DCD1 /* frameworks */, 206 | 86C39F0E126A1FA100A9DCD1 /* products */, 207 | 860E46A01A4F7B9E004C705B /* ios-ntp.framework */, 208 | 0746B65C32DF09349E67B6BC /* Pods */, 209 | CD5A1ECCCEC1E1850EAC6709 /* Frameworks */, 210 | ); 211 | sourceTree = ""; 212 | }; 213 | 86C39F08126A1FA100A9DCD1 /* frameworks */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 8661906E126C0CD70046A2B8 /* UIKit.framework */, 217 | 8661907A126C0CEC0046A2B8 /* Foundation.framework */, 218 | 86619081126C0CFD0046A2B8 /* CoreGraphics.framework */, 219 | 86619085126C0D120046A2B8 /* CFNetwork.framework */, 220 | ); 221 | name = frameworks; 222 | sourceTree = ""; 223 | }; 224 | 86C39F0E126A1FA100A9DCD1 /* products */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | 86C39F0D126A1FA100A9DCD1 /* ntp-app.app */, 228 | 86F300AE1A14815C0078CBF9 /* libios-lib.a */, 229 | 866F2B551A1D35A0008CCF83 /* ios_fwk.framework */, 230 | D9B2BA3F13D9B95100C9385A /* ios-ntp.tar.gz */, 231 | 865E539B1B20B3EF0048F8B1 /* ntp-test.xctest */, 232 | ); 233 | name = products; 234 | sourceTree = ""; 235 | }; 236 | 86C79ED61A1D657F00FC7CC2 /* ios-ntp-doc */ = { 237 | isa = PBXGroup; 238 | children = ( 239 | 867541861ACA2CD900D9990D /* ios-ntp.podspec */, 240 | 86C2B3F51A1DA95300481E2E /* rfc5905.pdf */, 241 | 863555321E09CA8100FB8E18 /* draft-ietf-ntp-bcp-02.pdf */, 242 | 86C79ED71A1D659F00FC7CC2 /* LICENSE */, 243 | 86C79ED81A1D659F00FC7CC2 /* README.md */, 244 | 862DA2551A999FC000F65F3E /* Notes */, 245 | ); 246 | name = "ios-ntp-doc"; 247 | sourceTree = ""; 248 | }; 249 | CD5A1ECCCEC1E1850EAC6709 /* Frameworks */ = { 250 | isa = PBXGroup; 251 | children = ( 252 | F53705249F4662D8943131E8 /* libPods-ios-lib.a */, 253 | 79CEE3E86E11635ED8F18631 /* libPods-ios_fwk.a */, 254 | C3914825A3B7B959A6C58FB6 /* libPods-ntp-app.a */, 255 | ); 256 | name = Frameworks; 257 | sourceTree = ""; 258 | }; 259 | D91E95D813D9AF8C004E4194 /* ios-ntp-lib */ = { 260 | isa = PBXGroup; 261 | children = ( 262 | D9B2BA3213D9B6CF00C9385A /* ios-ntp.h */, 263 | D9B2BA2C13D9B50200C9385A /* ntp-log.h */, 264 | D9B2BA4013D9C06100C9385A /* NSDate+NetworkClock.h */, 265 | D9B2BA4113D9C06100C9385A /* NSDate+NetworkClock.m */, 266 | D91E95D913D9AF8C004E4194 /* NetAssociation.h */, 267 | D91E95DA13D9AF8C004E4194 /* NetAssociation.m */, 268 | D91E95DB13D9AF8C004E4194 /* NetworkClock.h */, 269 | D91E95DC13D9AF8C004E4194 /* NetworkClock.m */, 270 | ); 271 | path = "ios-ntp-lib"; 272 | sourceTree = ""; 273 | }; 274 | D91E95DD13D9AF8C004E4194 /* ios-ntp-app */ = { 275 | isa = PBXGroup; 276 | children = ( 277 | D91E95F013D9B018004E4194 /* ntp-app-Info.plist */, 278 | 866ED2FE1B601121004E4394 /* ntp.hosts */, 279 | D91E95DE13D9AF8C004E4194 /* main.m */, 280 | 8602E82E1A1D5517001C265E /* ntpAppDelegate.h */, 281 | 8602E82F1A1D5517001C265E /* ntpAppDelegate.m */, 282 | 86CE9ED51A2841FB00AFDE79 /* ntpViewController.h */, 283 | 86CE9ED61A2841FB00AFDE79 /* ntpViewController.m */, 284 | 869A37D3259E31B8007C0DE2 /* GCDAsyncUdpSocket.h */, 285 | 869A37D2259E31B8007C0DE2 /* GCDAsyncUdpSocket.m */, 286 | ); 287 | path = "ios-ntp-app"; 288 | sourceTree = ""; 289 | }; 290 | D91E95E813D9B018004E4194 /* ios-ntp-rez */ = { 291 | isa = PBXGroup; 292 | children = ( 293 | D9B2BA2B13D9B50200C9385A /* ios-ntp-Info.plist */, 294 | D91E95F813D9B063004E4194 /* en.lproj */, 295 | ); 296 | path = "ios-ntp-rez"; 297 | sourceTree = ""; 298 | }; 299 | D91E95F813D9B063004E4194 /* en.lproj */ = { 300 | isa = PBXGroup; 301 | children = ( 302 | D91E95F913D9B063004E4194 /* InfoPlist.strings */, 303 | 86734BD51A2181FD00F191CE /* Storyboard.storyboard */, 304 | ); 305 | path = en.lproj; 306 | sourceTree = ""; 307 | }; 308 | /* End PBXGroup section */ 309 | 310 | /* Begin PBXHeadersBuildPhase section */ 311 | 866F2B521A1D35A0008CCF83 /* Headers */ = { 312 | isa = PBXHeadersBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | 866F2B751A1D35DE008CCF83 /* ios-ntp.h in Headers */, 316 | 86C2B3F71A1DAA1900481E2E /* NSDate+NetworkClock.h in Headers */, 317 | 86C2B3F81A1DAA1900481E2E /* NetAssociation.h in Headers */, 318 | 86C2B3F91A1DAA1900481E2E /* NetworkClock.h in Headers */, 319 | ); 320 | runOnlyForDeploymentPostprocessing = 0; 321 | }; 322 | /* End PBXHeadersBuildPhase section */ 323 | 324 | /* Begin PBXNativeTarget section */ 325 | 865E539A1B20B3EF0048F8B1 /* ntp-test */ = { 326 | isa = PBXNativeTarget; 327 | buildConfigurationList = 865E53A51B20B3EF0048F8B1 /* Build configuration list for PBXNativeTarget "ntp-test" */; 328 | buildPhases = ( 329 | 865E53971B20B3EF0048F8B1 /* Sources */, 330 | 865E53981B20B3EF0048F8B1 /* Frameworks */, 331 | 865E53991B20B3EF0048F8B1 /* Resources */, 332 | ); 333 | buildRules = ( 334 | ); 335 | dependencies = ( 336 | ); 337 | name = "ntp-test"; 338 | productName = "ntp-test"; 339 | productReference = 865E539B1B20B3EF0048F8B1 /* ntp-test.xctest */; 340 | productType = "com.apple.product-type.bundle.unit-test"; 341 | }; 342 | 866F2B541A1D35A0008CCF83 /* ios_fwk */ = { 343 | isa = PBXNativeTarget; 344 | buildConfigurationList = 866F2B6E1A1D35A0008CCF83 /* Build configuration list for PBXNativeTarget "ios_fwk" */; 345 | buildPhases = ( 346 | 866F2B501A1D35A0008CCF83 /* Sources */, 347 | 866F2B511A1D35A0008CCF83 /* Frameworks */, 348 | 866F2B521A1D35A0008CCF83 /* Headers */, 349 | 866F2B531A1D35A0008CCF83 /* Resources */, 350 | ); 351 | buildRules = ( 352 | ); 353 | dependencies = ( 354 | ); 355 | name = ios_fwk; 356 | productName = "ios-ntp-framework"; 357 | productReference = 866F2B551A1D35A0008CCF83 /* ios_fwk.framework */; 358 | productType = "com.apple.product-type.framework"; 359 | }; 360 | 86C39F0C126A1FA100A9DCD1 /* ntp-app */ = { 361 | isa = PBXNativeTarget; 362 | buildConfigurationList = 86C39F2B126A1FA100A9DCD1 /* Build configuration list for PBXNativeTarget "ntp-app" */; 363 | buildPhases = ( 364 | 86C39F09126A1FA100A9DCD1 /* Sources */, 365 | 86C39F0A126A1FA100A9DCD1 /* Frameworks */, 366 | 86C39F0B126A1FA100A9DCD1 /* Resources */, 367 | 866F2B711A1D35A0008CCF83 /* Embed Frameworks */, 368 | ); 369 | buildRules = ( 370 | ); 371 | dependencies = ( 372 | ); 373 | name = "ntp-app"; 374 | productName = ntpA; 375 | productReference = 86C39F0D126A1FA100A9DCD1 /* ntp-app.app */; 376 | productType = "com.apple.product-type.application"; 377 | }; 378 | 86F300AD1A14815C0078CBF9 /* ios-lib */ = { 379 | isa = PBXNativeTarget; 380 | buildConfigurationList = 86F300BF1A14815C0078CBF9 /* Build configuration list for PBXNativeTarget "ios-lib" */; 381 | buildPhases = ( 382 | 86F300AA1A14815C0078CBF9 /* Sources */, 383 | 86F300AB1A14815C0078CBF9 /* Frameworks */, 384 | 86F300AC1A14815C0078CBF9 /* CopyFiles */, 385 | ); 386 | buildRules = ( 387 | ); 388 | dependencies = ( 389 | ); 390 | name = "ios-lib"; 391 | productName = "ios-ntp"; 392 | productReference = 86F300AE1A14815C0078CBF9 /* libios-lib.a */; 393 | productType = "com.apple.product-type.library.static"; 394 | }; 395 | /* End PBXNativeTarget section */ 396 | 397 | /* Begin PBXProject section */ 398 | 86C39F00126A1FA000A9DCD1 /* Project object */ = { 399 | isa = PBXProject; 400 | attributes = { 401 | LastUpgradeCheck = 1230; 402 | ORGANIZATIONNAME = "Ramsay Consulting"; 403 | TargetAttributes = { 404 | 865E539A1B20B3EF0048F8B1 = { 405 | CreatedOnToolsVersion = 6.3.2; 406 | TestTargetID = 86C39F0C126A1FA100A9DCD1; 407 | }; 408 | 866F2B541A1D35A0008CCF83 = { 409 | CreatedOnToolsVersion = 6.1; 410 | }; 411 | 86C39F0C126A1FA100A9DCD1 = { 412 | DevelopmentTeam = CXE9ZR7J3U; 413 | ProvisioningStyle = Automatic; 414 | }; 415 | 86F300AD1A14815C0078CBF9 = { 416 | CreatedOnToolsVersion = 6.1; 417 | }; 418 | }; 419 | }; 420 | buildConfigurationList = 86C39F03126A1FA000A9DCD1 /* Build configuration list for PBXProject "ios-ntp" */; 421 | compatibilityVersion = "Xcode 9.3"; 422 | developmentRegion = en; 423 | hasScannedForEncodings = 0; 424 | knownRegions = ( 425 | en, 426 | Base, 427 | ); 428 | mainGroup = 86C39EFE126A1FA000A9DCD1; 429 | productRefGroup = 86C39F0E126A1FA100A9DCD1 /* products */; 430 | projectDirPath = ""; 431 | projectRoot = ""; 432 | targets = ( 433 | 86C39F0C126A1FA100A9DCD1 /* ntp-app */, 434 | 86F300AD1A14815C0078CBF9 /* ios-lib */, 435 | 866F2B541A1D35A0008CCF83 /* ios_fwk */, 436 | 865E539A1B20B3EF0048F8B1 /* ntp-test */, 437 | ); 438 | }; 439 | /* End PBXProject section */ 440 | 441 | /* Begin PBXResourcesBuildPhase section */ 442 | 865E53991B20B3EF0048F8B1 /* Resources */ = { 443 | isa = PBXResourcesBuildPhase; 444 | buildActionMask = 2147483647; 445 | files = ( 446 | ); 447 | runOnlyForDeploymentPostprocessing = 0; 448 | }; 449 | 866F2B531A1D35A0008CCF83 /* Resources */ = { 450 | isa = PBXResourcesBuildPhase; 451 | buildActionMask = 2147483647; 452 | files = ( 453 | ); 454 | runOnlyForDeploymentPostprocessing = 0; 455 | }; 456 | 86C39F0B126A1FA100A9DCD1 /* Resources */ = { 457 | isa = PBXResourcesBuildPhase; 458 | buildActionMask = 2147483647; 459 | files = ( 460 | 863555311E09976D00FB8E18 /* ntp.hosts in Resources */, 461 | 130140C620C5A0F4003D167F /* Default-568h@2x.png in Resources */, 462 | 86734BD71A2181FD00F191CE /* Storyboard.storyboard in Resources */, 463 | D91E95FF13D9B063004E4194 /* InfoPlist.strings in Resources */, 464 | ); 465 | runOnlyForDeploymentPostprocessing = 0; 466 | }; 467 | /* End PBXResourcesBuildPhase section */ 468 | 469 | /* Begin PBXSourcesBuildPhase section */ 470 | 865E53971B20B3EF0048F8B1 /* Sources */ = { 471 | isa = PBXSourcesBuildPhase; 472 | buildActionMask = 2147483647; 473 | files = ( 474 | 869A37D7259E31B8007C0DE2 /* GCDAsyncUdpSocket.m in Sources */, 475 | 865E53A01B20B3EF0048F8B1 /* ntp_test.m in Sources */, 476 | ); 477 | runOnlyForDeploymentPostprocessing = 0; 478 | }; 479 | 866F2B501A1D35A0008CCF83 /* Sources */ = { 480 | isa = PBXSourcesBuildPhase; 481 | buildActionMask = 2147483647; 482 | files = ( 483 | 869A37D6259E31B8007C0DE2 /* GCDAsyncUdpSocket.m in Sources */, 484 | 866F2B771A1D3624008CCF83 /* NSDate+NetworkClock.m in Sources */, 485 | 866F2B781A1D3624008CCF83 /* NetAssociation.m in Sources */, 486 | 866F2B791A1D3624008CCF83 /* NetworkClock.m in Sources */, 487 | ); 488 | runOnlyForDeploymentPostprocessing = 0; 489 | }; 490 | 86C39F09126A1FA100A9DCD1 /* Sources */ = { 491 | isa = PBXSourcesBuildPhase; 492 | buildActionMask = 2147483647; 493 | files = ( 494 | D91E95E513D9AF8C004E4194 /* main.m in Sources */, 495 | 8602E8321A1D5517001C265E /* ntpAppDelegate.m in Sources */, 496 | 86CE9ED71A2841FB00AFDE79 /* ntpViewController.m in Sources */, 497 | 86273CCB1A1AACBB00487A18 /* NSDate+NetworkClock.m in Sources */, 498 | 869A7CDB1A1AB0AC00067303 /* NetAssociation.m in Sources */, 499 | 869A7CDC1A1AB0AC00067303 /* NetworkClock.m in Sources */, 500 | 869A37D4259E31B8007C0DE2 /* GCDAsyncUdpSocket.m in Sources */, 501 | ); 502 | runOnlyForDeploymentPostprocessing = 0; 503 | }; 504 | 86F300AA1A14815C0078CBF9 /* Sources */ = { 505 | isa = PBXSourcesBuildPhase; 506 | buildActionMask = 2147483647; 507 | files = ( 508 | 869A37D5259E31B8007C0DE2 /* GCDAsyncUdpSocket.m in Sources */, 509 | 86F300CC1A1483900078CBF9 /* NSDate+NetworkClock.m in Sources */, 510 | 86F300C61A1481C00078CBF9 /* NetAssociation.m in Sources */, 511 | 86F300C81A1481C00078CBF9 /* NetworkClock.m in Sources */, 512 | ); 513 | runOnlyForDeploymentPostprocessing = 0; 514 | }; 515 | /* End PBXSourcesBuildPhase section */ 516 | 517 | /* Begin PBXVariantGroup section */ 518 | 86734BD51A2181FD00F191CE /* Storyboard.storyboard */ = { 519 | isa = PBXVariantGroup; 520 | children = ( 521 | 86734BD61A2181FD00F191CE /* en */, 522 | ); 523 | name = Storyboard.storyboard; 524 | sourceTree = ""; 525 | }; 526 | D91E95F913D9B063004E4194 /* InfoPlist.strings */ = { 527 | isa = PBXVariantGroup; 528 | children = ( 529 | D91E95FA13D9B063004E4194 /* en */, 530 | ); 531 | name = InfoPlist.strings; 532 | sourceTree = ""; 533 | }; 534 | /* End PBXVariantGroup section */ 535 | 536 | /* Begin XCBuildConfiguration section */ 537 | 865E53A31B20B3EF0048F8B1 /* Debug */ = { 538 | isa = XCBuildConfiguration; 539 | buildSettings = { 540 | ALWAYS_SEARCH_USER_PATHS = NO; 541 | BUNDLE_LOADER = "$(TEST_HOST)"; 542 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 543 | CLANG_CXX_LIBRARY = "libc++"; 544 | CLANG_ENABLE_MODULES = YES; 545 | CLANG_WARN_BOOL_CONVERSION = YES; 546 | CLANG_WARN_CONSTANT_CONVERSION = YES; 547 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 548 | CLANG_WARN_EMPTY_BODY = YES; 549 | CLANG_WARN_ENUM_CONVERSION = YES; 550 | CLANG_WARN_INT_CONVERSION = YES; 551 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 552 | CLANG_WARN_UNREACHABLE_CODE = YES; 553 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 554 | COPY_PHASE_STRIP = NO; 555 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 556 | ENABLE_STRICT_OBJC_MSGSEND = YES; 557 | FRAMEWORK_SEARCH_PATHS = ( 558 | "$(SDKROOT)/Developer/Library/Frameworks", 559 | "$(inherited)", 560 | ); 561 | GCC_C_LANGUAGE_STANDARD = gnu99; 562 | GCC_DYNAMIC_NO_PIC = NO; 563 | GCC_NO_COMMON_BLOCKS = YES; 564 | GCC_PREPROCESSOR_DEFINITIONS = ( 565 | "DEBUG=1", 566 | "$(inherited)", 567 | ); 568 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 569 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 570 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 571 | GCC_WARN_UNDECLARED_SELECTOR = YES; 572 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 573 | GCC_WARN_UNUSED_FUNCTION = YES; 574 | INFOPLIST_FILE = "ntp-test/Info.plist"; 575 | LD_RUNPATH_SEARCH_PATHS = ( 576 | "$(inherited)", 577 | "@executable_path/Frameworks", 578 | "@loader_path/Frameworks", 579 | ); 580 | MTL_ENABLE_DEBUG_INFO = YES; 581 | PRODUCT_BUNDLE_IDENTIFIER = "com.ramsaycons.$(PRODUCT_NAME:rfc1034identifier)"; 582 | PRODUCT_NAME = "$(TARGET_NAME)"; 583 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ntp-app.app/ntp-app"; 584 | }; 585 | name = Debug; 586 | }; 587 | 865E53A41B20B3EF0048F8B1 /* Release */ = { 588 | isa = XCBuildConfiguration; 589 | buildSettings = { 590 | ALWAYS_SEARCH_USER_PATHS = NO; 591 | BUNDLE_LOADER = "$(TEST_HOST)"; 592 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 593 | CLANG_CXX_LIBRARY = "libc++"; 594 | CLANG_ENABLE_MODULES = YES; 595 | CLANG_WARN_BOOL_CONVERSION = YES; 596 | CLANG_WARN_CONSTANT_CONVERSION = YES; 597 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 598 | CLANG_WARN_EMPTY_BODY = YES; 599 | CLANG_WARN_ENUM_CONVERSION = YES; 600 | CLANG_WARN_INT_CONVERSION = YES; 601 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 602 | CLANG_WARN_UNREACHABLE_CODE = YES; 603 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 604 | COPY_PHASE_STRIP = NO; 605 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 606 | ENABLE_NS_ASSERTIONS = NO; 607 | ENABLE_STRICT_OBJC_MSGSEND = YES; 608 | FRAMEWORK_SEARCH_PATHS = ( 609 | "$(SDKROOT)/Developer/Library/Frameworks", 610 | "$(inherited)", 611 | ); 612 | GCC_C_LANGUAGE_STANDARD = gnu99; 613 | GCC_NO_COMMON_BLOCKS = YES; 614 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 615 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 616 | GCC_WARN_UNDECLARED_SELECTOR = YES; 617 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 618 | GCC_WARN_UNUSED_FUNCTION = YES; 619 | INFOPLIST_FILE = "ntp-test/Info.plist"; 620 | LD_RUNPATH_SEARCH_PATHS = ( 621 | "$(inherited)", 622 | "@executable_path/Frameworks", 623 | "@loader_path/Frameworks", 624 | ); 625 | MTL_ENABLE_DEBUG_INFO = NO; 626 | PRODUCT_BUNDLE_IDENTIFIER = "com.ramsaycons.$(PRODUCT_NAME:rfc1034identifier)"; 627 | PRODUCT_NAME = "$(TARGET_NAME)"; 628 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ntp-app.app/ntp-app"; 629 | VALIDATE_PRODUCT = YES; 630 | }; 631 | name = Release; 632 | }; 633 | 866F2B6F1A1D35A0008CCF83 /* Debug */ = { 634 | isa = XCBuildConfiguration; 635 | baseConfigurationReference = 068C40DC398F9AD4AAAFE3D5 /* Pods-ios_fwk.debug.xcconfig */; 636 | buildSettings = { 637 | ALWAYS_SEARCH_USER_PATHS = NO; 638 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 639 | CLANG_CXX_LIBRARY = "libc++"; 640 | CLANG_ENABLE_MODULES = YES; 641 | CLANG_WARN_BOOL_CONVERSION = YES; 642 | CLANG_WARN_CONSTANT_CONVERSION = YES; 643 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 644 | CLANG_WARN_EMPTY_BODY = YES; 645 | CLANG_WARN_ENUM_CONVERSION = YES; 646 | CLANG_WARN_INT_CONVERSION = YES; 647 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 648 | CLANG_WARN_UNREACHABLE_CODE = YES; 649 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 650 | COPY_PHASE_STRIP = NO; 651 | CURRENT_PROJECT_VERSION = 1; 652 | DEFINES_MODULE = YES; 653 | DYLIB_COMPATIBILITY_VERSION = 1; 654 | DYLIB_CURRENT_VERSION = 1; 655 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 656 | ENABLE_STRICT_OBJC_MSGSEND = YES; 657 | GCC_DYNAMIC_NO_PIC = NO; 658 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 659 | GCC_PREFIX_HEADER = ""; 660 | GCC_PREPROCESSOR_DEFINITIONS = ( 661 | "DEBUG=1", 662 | "$(inherited)", 663 | ); 664 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 665 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 666 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 667 | GCC_WARN_UNDECLARED_SELECTOR = YES; 668 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 669 | GCC_WARN_UNUSED_FUNCTION = YES; 670 | HEADER_SEARCH_PATHS = ""; 671 | INFOPLIST_FILE = "$(SRCROOT)/ios-ntp-rez/ios-ntp-Info.plist"; 672 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 673 | LD_RUNPATH_SEARCH_PATHS = ( 674 | "$(inherited)", 675 | "@executable_path/Frameworks", 676 | "@loader_path/Frameworks", 677 | ); 678 | LIBRARY_SEARCH_PATHS = ""; 679 | MTL_ENABLE_DEBUG_INFO = YES; 680 | ONLY_ACTIVE_ARCH = YES; 681 | OTHER_CFLAGS = ""; 682 | OTHER_LDFLAGS = ""; 683 | PRODUCT_BUNDLE_IDENTIFIER = "org.framework.ios-ntp"; 684 | PRODUCT_NAME = "$(TARGET_NAME)"; 685 | SKIP_INSTALL = YES; 686 | TARGETED_DEVICE_FAMILY = "1,2"; 687 | VERSIONING_SYSTEM = "apple-generic"; 688 | }; 689 | name = Debug; 690 | }; 691 | 866F2B701A1D35A0008CCF83 /* Release */ = { 692 | isa = XCBuildConfiguration; 693 | baseConfigurationReference = 460FC93E8F7E2C8B724597B1 /* Pods-ios_fwk.release.xcconfig */; 694 | buildSettings = { 695 | ALWAYS_SEARCH_USER_PATHS = NO; 696 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 697 | CLANG_CXX_LIBRARY = "libc++"; 698 | CLANG_ENABLE_MODULES = YES; 699 | CLANG_WARN_BOOL_CONVERSION = YES; 700 | CLANG_WARN_CONSTANT_CONVERSION = YES; 701 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 702 | CLANG_WARN_EMPTY_BODY = YES; 703 | CLANG_WARN_ENUM_CONVERSION = YES; 704 | CLANG_WARN_INT_CONVERSION = YES; 705 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 706 | CLANG_WARN_UNREACHABLE_CODE = YES; 707 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 708 | COPY_PHASE_STRIP = YES; 709 | CURRENT_PROJECT_VERSION = 1; 710 | DEFINES_MODULE = YES; 711 | DYLIB_COMPATIBILITY_VERSION = 1; 712 | DYLIB_CURRENT_VERSION = 1; 713 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 714 | ENABLE_NS_ASSERTIONS = NO; 715 | ENABLE_STRICT_OBJC_MSGSEND = YES; 716 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 717 | GCC_PREFIX_HEADER = ""; 718 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 719 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 720 | GCC_WARN_UNDECLARED_SELECTOR = YES; 721 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 722 | GCC_WARN_UNUSED_FUNCTION = YES; 723 | HEADER_SEARCH_PATHS = ""; 724 | INFOPLIST_FILE = "$(SRCROOT)/ios-ntp-rez/ios-ntp-Info.plist"; 725 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 726 | LD_RUNPATH_SEARCH_PATHS = ( 727 | "$(inherited)", 728 | "@executable_path/Frameworks", 729 | "@loader_path/Frameworks", 730 | ); 731 | LIBRARY_SEARCH_PATHS = ""; 732 | MTL_ENABLE_DEBUG_INFO = NO; 733 | OTHER_CFLAGS = ""; 734 | OTHER_LDFLAGS = ""; 735 | PRODUCT_BUNDLE_IDENTIFIER = "org.framework.ios-ntp"; 736 | PRODUCT_NAME = "$(TARGET_NAME)"; 737 | SKIP_INSTALL = YES; 738 | TARGETED_DEVICE_FAMILY = "1,2"; 739 | VALIDATE_PRODUCT = YES; 740 | VERSIONING_SYSTEM = "apple-generic"; 741 | }; 742 | name = Release; 743 | }; 744 | 86C39F29126A1FA100A9DCD1 /* Debug */ = { 745 | isa = XCBuildConfiguration; 746 | buildSettings = { 747 | ALWAYS_SEARCH_USER_PATHS = NO; 748 | CLANG_ENABLE_OBJC_ARC = YES; 749 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 750 | CLANG_WARN_BOOL_CONVERSION = YES; 751 | CLANG_WARN_COMMA = YES; 752 | CLANG_WARN_CONSTANT_CONVERSION = YES; 753 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 754 | CLANG_WARN_EMPTY_BODY = YES; 755 | CLANG_WARN_ENUM_CONVERSION = YES; 756 | CLANG_WARN_INFINITE_RECURSION = YES; 757 | CLANG_WARN_INT_CONVERSION = YES; 758 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 759 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 760 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 761 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 762 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 763 | CLANG_WARN_STRICT_PROTOTYPES = YES; 764 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 765 | CLANG_WARN_UNREACHABLE_CODE = YES; 766 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 767 | CODE_SIGN_IDENTITY = ""; 768 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 769 | ENABLE_STRICT_OBJC_MSGSEND = YES; 770 | ENABLE_TESTABILITY = YES; 771 | GCC_NO_COMMON_BLOCKS = YES; 772 | GCC_OPTIMIZATION_LEVEL = 0; 773 | GCC_PREPROCESSOR_DEFINITIONS = IOS_NTP_LOGGING; 774 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 775 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 776 | GCC_WARN_UNDECLARED_SELECTOR = YES; 777 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 778 | GCC_WARN_UNUSED_FUNCTION = YES; 779 | GCC_WARN_UNUSED_VARIABLE = YES; 780 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 781 | ONLY_ACTIVE_ARCH = YES; 782 | SDKROOT = iphoneos; 783 | TARGETED_DEVICE_FAMILY = "1,2"; 784 | USER_HEADER_SEARCH_PATHS = "$SRCROOT/**"; 785 | }; 786 | name = Debug; 787 | }; 788 | 86C39F2A126A1FA100A9DCD1 /* Release */ = { 789 | isa = XCBuildConfiguration; 790 | buildSettings = { 791 | ALWAYS_SEARCH_USER_PATHS = NO; 792 | CLANG_ENABLE_OBJC_ARC = YES; 793 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 794 | CLANG_WARN_BOOL_CONVERSION = YES; 795 | CLANG_WARN_COMMA = YES; 796 | CLANG_WARN_CONSTANT_CONVERSION = YES; 797 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 798 | CLANG_WARN_EMPTY_BODY = YES; 799 | CLANG_WARN_ENUM_CONVERSION = YES; 800 | CLANG_WARN_INFINITE_RECURSION = YES; 801 | CLANG_WARN_INT_CONVERSION = YES; 802 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 803 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 804 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 805 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 806 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 807 | CLANG_WARN_STRICT_PROTOTYPES = YES; 808 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 809 | CLANG_WARN_UNREACHABLE_CODE = YES; 810 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 811 | CODE_SIGN_IDENTITY = ""; 812 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 813 | ENABLE_STRICT_OBJC_MSGSEND = YES; 814 | GCC_NO_COMMON_BLOCKS = YES; 815 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 816 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 817 | GCC_WARN_UNDECLARED_SELECTOR = YES; 818 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 819 | GCC_WARN_UNUSED_FUNCTION = YES; 820 | GCC_WARN_UNUSED_VARIABLE = YES; 821 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 822 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 823 | SDKROOT = iphoneos; 824 | TARGETED_DEVICE_FAMILY = "1,2"; 825 | USER_HEADER_SEARCH_PATHS = "$SRCROOT/**"; 826 | }; 827 | name = Release; 828 | }; 829 | 86C39F2C126A1FA100A9DCD1 /* Debug */ = { 830 | isa = XCBuildConfiguration; 831 | baseConfigurationReference = 13889D35CCF867F7048E444B /* Pods-ntp-app.debug.xcconfig */; 832 | buildSettings = { 833 | ALWAYS_SEARCH_USER_PATHS = NO; 834 | CLANG_ENABLE_OBJC_ARC = YES; 835 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 836 | CODE_SIGN_STYLE = Automatic; 837 | COPY_PHASE_STRIP = NO; 838 | DEVELOPMENT_TEAM = CXE9ZR7J3U; 839 | GCC_DYNAMIC_NO_PIC = NO; 840 | GCC_PREPROCESSOR_DEFINITIONS = IOS_NTP_LOGGING; 841 | GCC_VERSION = ""; 842 | HEADER_SEARCH_PATHS = ""; 843 | INFOPLIST_FILE = "ios-ntp-rez/ntp-app-Info.plist"; 844 | LD_RUNPATH_SEARCH_PATHS = ( 845 | "$(inherited)", 846 | "@executable_path/Frameworks", 847 | ); 848 | LIBRARY_SEARCH_PATHS = ""; 849 | "LIBRARY_SEARCH_PATHS[arch=*]" = ""; 850 | OTHER_CFLAGS = ""; 851 | OTHER_LDFLAGS = ""; 852 | PRODUCT_BUNDLE_IDENTIFIER = "com.ramsaycons.${PRODUCT_NAME:rfc1034identifier}"; 853 | PRODUCT_NAME = "$(TARGET_NAME)"; 854 | PROVISIONING_PROFILE_SPECIFIER = ""; 855 | TARGETED_DEVICE_FAMILY = 1; 856 | WRAPPER_EXTENSION = app; 857 | }; 858 | name = Debug; 859 | }; 860 | 86C39F2D126A1FA100A9DCD1 /* Release */ = { 861 | isa = XCBuildConfiguration; 862 | baseConfigurationReference = 70F61A313E882D3E270D6406 /* Pods-ntp-app.release.xcconfig */; 863 | buildSettings = { 864 | ALWAYS_SEARCH_USER_PATHS = NO; 865 | CLANG_ENABLE_OBJC_ARC = YES; 866 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 867 | CODE_SIGN_STYLE = Automatic; 868 | COPY_PHASE_STRIP = YES; 869 | DEVELOPMENT_TEAM = CXE9ZR7J3U; 870 | GCC_VERSION = ""; 871 | HEADER_SEARCH_PATHS = ""; 872 | INFOPLIST_FILE = "ios-ntp-rez/ntp-app-Info.plist"; 873 | LD_RUNPATH_SEARCH_PATHS = ( 874 | "$(inherited)", 875 | "@executable_path/Frameworks", 876 | ); 877 | LIBRARY_SEARCH_PATHS = ""; 878 | OTHER_CFLAGS = ""; 879 | OTHER_LDFLAGS = ""; 880 | PRODUCT_BUNDLE_IDENTIFIER = "com.ramsaycons.${PRODUCT_NAME:rfc1034identifier}"; 881 | PRODUCT_NAME = "$(TARGET_NAME)"; 882 | PROVISIONING_PROFILE_SPECIFIER = ""; 883 | TARGETED_DEVICE_FAMILY = 1; 884 | VALIDATE_PRODUCT = YES; 885 | WRAPPER_EXTENSION = app; 886 | }; 887 | name = Release; 888 | }; 889 | 86F300C01A14815C0078CBF9 /* Debug */ = { 890 | isa = XCBuildConfiguration; 891 | baseConfigurationReference = C9351D630EE6593D82FB2588 /* Pods-ios-lib.debug.xcconfig */; 892 | buildSettings = { 893 | CLANG_WARN_BOOL_CONVERSION = YES; 894 | CLANG_WARN_CONSTANT_CONVERSION = YES; 895 | CLANG_WARN_EMPTY_BODY = YES; 896 | CLANG_WARN_ENUM_CONVERSION = YES; 897 | CLANG_WARN_INT_CONVERSION = YES; 898 | CLANG_WARN_UNREACHABLE_CODE = YES; 899 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 900 | COPY_PHASE_STRIP = NO; 901 | ENABLE_STRICT_OBJC_MSGSEND = YES; 902 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 903 | GCC_PREPROCESSOR_DEFINITIONS = ( 904 | "DEBUG=1", 905 | "$(inherited)", 906 | ); 907 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 908 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 909 | GCC_WARN_UNDECLARED_SELECTOR = YES; 910 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 911 | GCC_WARN_UNUSED_FUNCTION = YES; 912 | HEADER_SEARCH_PATHS = ""; 913 | LIBRARY_SEARCH_PATHS = ""; 914 | MTL_ENABLE_DEBUG_INFO = YES; 915 | ONLY_ACTIVE_ARCH = YES; 916 | OTHER_CFLAGS = ""; 917 | OTHER_LDFLAGS = ""; 918 | PRODUCT_NAME = "$(TARGET_NAME)"; 919 | SKIP_INSTALL = YES; 920 | }; 921 | name = Debug; 922 | }; 923 | 86F300C11A14815C0078CBF9 /* Release */ = { 924 | isa = XCBuildConfiguration; 925 | baseConfigurationReference = 6327AF9F37F7C9F740A08306 /* Pods-ios-lib.release.xcconfig */; 926 | buildSettings = { 927 | CLANG_WARN_BOOL_CONVERSION = YES; 928 | CLANG_WARN_CONSTANT_CONVERSION = YES; 929 | CLANG_WARN_EMPTY_BODY = YES; 930 | CLANG_WARN_ENUM_CONVERSION = YES; 931 | CLANG_WARN_INT_CONVERSION = YES; 932 | CLANG_WARN_UNREACHABLE_CODE = YES; 933 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 934 | COPY_PHASE_STRIP = YES; 935 | ENABLE_NS_ASSERTIONS = NO; 936 | ENABLE_STRICT_OBJC_MSGSEND = YES; 937 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 938 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 939 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 940 | GCC_WARN_UNDECLARED_SELECTOR = YES; 941 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 942 | GCC_WARN_UNUSED_FUNCTION = YES; 943 | HEADER_SEARCH_PATHS = ""; 944 | LIBRARY_SEARCH_PATHS = ""; 945 | MTL_ENABLE_DEBUG_INFO = NO; 946 | OTHER_CFLAGS = ""; 947 | OTHER_LDFLAGS = ""; 948 | PRODUCT_NAME = "$(TARGET_NAME)"; 949 | SKIP_INSTALL = YES; 950 | VALIDATE_PRODUCT = YES; 951 | }; 952 | name = Release; 953 | }; 954 | /* End XCBuildConfiguration section */ 955 | 956 | /* Begin XCConfigurationList section */ 957 | 865E53A51B20B3EF0048F8B1 /* Build configuration list for PBXNativeTarget "ntp-test" */ = { 958 | isa = XCConfigurationList; 959 | buildConfigurations = ( 960 | 865E53A31B20B3EF0048F8B1 /* Debug */, 961 | 865E53A41B20B3EF0048F8B1 /* Release */, 962 | ); 963 | defaultConfigurationIsVisible = 0; 964 | defaultConfigurationName = Release; 965 | }; 966 | 866F2B6E1A1D35A0008CCF83 /* Build configuration list for PBXNativeTarget "ios_fwk" */ = { 967 | isa = XCConfigurationList; 968 | buildConfigurations = ( 969 | 866F2B6F1A1D35A0008CCF83 /* Debug */, 970 | 866F2B701A1D35A0008CCF83 /* Release */, 971 | ); 972 | defaultConfigurationIsVisible = 0; 973 | defaultConfigurationName = Release; 974 | }; 975 | 86C39F03126A1FA000A9DCD1 /* Build configuration list for PBXProject "ios-ntp" */ = { 976 | isa = XCConfigurationList; 977 | buildConfigurations = ( 978 | 86C39F29126A1FA100A9DCD1 /* Debug */, 979 | 86C39F2A126A1FA100A9DCD1 /* Release */, 980 | ); 981 | defaultConfigurationIsVisible = 0; 982 | defaultConfigurationName = Release; 983 | }; 984 | 86C39F2B126A1FA100A9DCD1 /* Build configuration list for PBXNativeTarget "ntp-app" */ = { 985 | isa = XCConfigurationList; 986 | buildConfigurations = ( 987 | 86C39F2C126A1FA100A9DCD1 /* Debug */, 988 | 86C39F2D126A1FA100A9DCD1 /* Release */, 989 | ); 990 | defaultConfigurationIsVisible = 0; 991 | defaultConfigurationName = Release; 992 | }; 993 | 86F300BF1A14815C0078CBF9 /* Build configuration list for PBXNativeTarget "ios-lib" */ = { 994 | isa = XCConfigurationList; 995 | buildConfigurations = ( 996 | 86F300C01A14815C0078CBF9 /* Debug */, 997 | 86F300C11A14815C0078CBF9 /* Release */, 998 | ); 999 | defaultConfigurationIsVisible = 0; 1000 | defaultConfigurationName = Release; 1001 | }; 1002 | /* End XCConfigurationList section */ 1003 | }; 1004 | rootObject = 86C39F00126A1FA000A9DCD1 /* Project object */; 1005 | } 1006 | --------------------------------------------------------------------------------