Browse files

Eliminated requirement to use -all_load linker flag. Fixed breakage i…

…n OS X builds due to ivar/property name disagreement. Removed references to all_load from the install docs. fixes #239
  • Loading branch information...
1 parent 7ca39d8 commit b96940cc6427381e8b4afce47aa9f30667314a14 @blakewatters blakewatters committed Sep 1, 2011
Showing with 107 additions and 2,717 deletions.
  1. +3 −0 Code/CoreData/NSManagedObject+ActiveRecord.m
  2. +3 −0 Code/CoreData/RKObjectPropertyInspector+CoreData.m
  3. +4 −1 Code/Network/NSData+MD5.m
  4. +3 −0 Code/Network/NSDictionary+RKRequestSerialization.m
  5. +4 −1 Code/Network/NSString+MD5.m
  6. +1 −0 Code/Network/RKClient.h
  7. +1 −0 Code/Network/RKRequest.h
  8. +1 −0 Code/Network/RKRequestQueue.h
  9. +4 −0 Code/Network/RKRequestQueue.m
  10. +3 −0 Code/Support/NSDictionary+RKAdditions.m
  11. +3 −0 Code/Support/NSString+InflectionSupport.m
  12. +1 −1 Code/Support/NSString+RestKit.h
  13. +3 −0 Code/Support/NSString+RestKit.m
  14. +23 −0 Code/Support/RKFixCategoryBug.h
  15. +5 −3 Examples/RKCatalog/RKCatalog.xcodeproj/project.pbxproj
  16. +5 −11 Examples/RKDiscussionBoardExample/DiscussionBoard/DiscussionBoard.xcodeproj/project.pbxproj
  17. +7 −11 Examples/RKMacOSX/RKMacOSX.xcodeproj/project.pbxproj
  18. +5 −11 Examples/RKTwitter/RKTwitter.xcodeproj/project.pbxproj
  19. +7 −19 Examples/RKTwitterCoreData/RKTwitterCoreData.xcodeproj/project.pbxproj
  20. +3 −3 README.md
  21. +4 −27 RestKit.xcodeproj/project.pbxproj
  22. +0 −23 Vendor/NSLogger/LICENSE.txt
  23. +0 −227 Vendor/NSLogger/LoggerClient.h
  24. +0 −2,193 Vendor/NSLogger/LoggerClient.m
  25. +0 −113 Vendor/NSLogger/LoggerCommon.h
  26. +0 −73 Vendor/NSLogger/README.markdown
  27. +2 −0 Vendor/NXJSON/NSError+Extensions.m
  28. +3 −0 Vendor/SBJSON/NSObject+SBJSON.m
  29. +3 −0 Vendor/SBJSON/NSString+SBJSON.m
  30. +3 −0 Vendor/YAJL/NSBundle+YAJL.m
  31. +3 −0 Vendor/YAJL/NSObject+YAJL.m
View
3 Code/CoreData/NSManagedObject+ActiveRecord.m
@@ -12,6 +12,9 @@
#import "NSManagedObject+ActiveRecord.h"
#import "RKObjectManager.h"
#import "RKLog.h"
+#import "../Support/RKFixCategoryBug.h"
+
+RK_FIX_CATEGORY_BUG(NSManagedObject_ActiveRecord)
// Set Logging Component
#undef RKLogComponent
View
3 Code/CoreData/RKObjectPropertyInspector+CoreData.m
@@ -9,6 +9,9 @@
#import <CoreData/CoreData.h>
#import "RKObjectPropertyInspector+CoreData.h"
#import "../Support/RKLog.h"
+#import "../Support/RKFixCategoryBug.h"
+
+RK_FIX_CATEGORY_BUG(RKObjectPropertyInspector_CoreData)
// Set Logging Component
#undef RKLogComponent
View
5 Code/Network/NSData+MD5.m
@@ -6,8 +6,11 @@
// Copyright 2011 Two Toasters. All rights reserved.
//
-#import "NSData+MD5.h"
#import <CommonCrypto/CommonDigest.h>
+#import "NSData+MD5.h"
+#import "../Support/RKFixCategoryBug.h"
+
+RK_FIX_CATEGORY_BUG(NSData_MD5)
@implementation NSData (MD5)
View
3 Code/Network/NSDictionary+RKRequestSerialization.m
@@ -7,6 +7,9 @@
//
#import "NSDictionary+RKRequestSerialization.h"
+#import "../Support/RKFixCategoryBug.h"
+
+RK_FIX_CATEGORY_BUG(NSDictionary_RKRequestSerialization)
/**
* private helper function to convert any object to its string representation
View
5 Code/Network/NSString+MD5.m
@@ -6,8 +6,11 @@
// Copyright 2011 Two Toasters. All rights reserved.
//
-#import "NSString+MD5.h"
#import <CommonCrypto/CommonDigest.h>
+#import "NSString+MD5.h"
+#import "../Support/RKFixCategoryBug.h"
+
+RK_FIX_CATEGORY_BUG(NSString_MD5)
@implementation NSString (MD5)
View
1 Code/Network/RKClient.h
@@ -129,6 +129,7 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
NSString* _serviceUnavailableAlertTitle;
NSString* _serviceUnavailableAlertMessage;
BOOL _serviceUnavailableAlertEnabled;
+ RKRequestQueue *_requestQueue;
RKRequestCache* _cache;
RKRequestCachePolicy _cachePolicy;
NSMutableSet *_additionalRootCertificates;
View
1 Code/Network/RKRequest.h
@@ -90,6 +90,7 @@ typedef enum RKRequestBackgroundPolicy {
BOOL _forceBasicAuthentication;
RKRequestCache* _cache;
NSTimeInterval _cacheTimeoutInterval;
+ RKRequestQueue *_queue;
#if TARGET_OS_IPHONE
RKRequestBackgroundPolicy _backgroundPolicy;
View
1 Code/Network/RKRequestQueue.h
@@ -16,6 +16,7 @@
* for dispatching and managing RKRequest objects
*/
@interface RKRequestQueue : NSObject {
+ NSString *_name;
NSMutableArray* _requests;
NSObject<RKRequestQueueDelegate>* _delegate;
NSUInteger _loadingCount;
View
4 Code/Network/RKRequestQueue.m
@@ -14,7 +14,11 @@
#import "RKResponse.h"
#import "RKNotifications.h"
#import "../Support/RKLog.h"
+#import "../Support/RKFixCategoryBug.h"
+RK_FIX_CATEGORY_BUG(UIApplication_RKNetworkActivity)
+
+// Constants
static RKRequestQueue* RKRequestQueueSharedQueue = nil;
static NSMutableArray* RKRequestQueueInstances = nil;
View
3 Code/Support/NSDictionary+RKAdditions.m
@@ -7,6 +7,9 @@
//
#import "NSDictionary+RKAdditions.h"
+#import "RKFixCategoryBug.h"
+
+RK_FIX_CATEGORY_BUG(NSDictionary_RKAdditions)
@implementation NSDictionary (RKAdditions)
View
3 Code/Support/NSString+InflectionSupport.m
@@ -7,6 +7,9 @@
//
#import "NSString+InflectionSupport.h"
+#import "RKFixCategoryBug.h"
+
+RK_FIX_CATEGORY_BUG(NSString_InflectionSupport)
@implementation NSString (InflectionSupport)
View
2 Code/Support/NSString+RestKit.h
@@ -12,7 +12,7 @@
A library of helpful additions to the NSString class to simplify
common tasks within RestKit
*/
-@interface NSString (NSString)
+@interface NSString (RestKit)
/**
Returns a resource path with a dictionary of query parameters URL encoded and appended
View
3 Code/Support/NSString+RestKit.m
@@ -8,6 +8,9 @@
#import "NSString+RestKit.h"
#import "../Network/RKClient.h"
+#import "RKFixCategoryBug.h"
+
+RK_FIX_CATEGORY_BUG(NSString_RestKit)
@implementation NSString (RestKit)
View
23 Code/Support/RKFixCategoryBug.h
@@ -0,0 +1,23 @@
+//
+// RKCategoryFix.h
+// RestKit
+//
+// Created by Blake Watters on 9/1/11.
+// Copyright (c) 2011 RestKit. All rights reserved.
+//
+
+#ifndef RestKit_RKCategoryFix_h
+#define RestKit_RKCategoryFix_h
+
+/**
+ Add this macro before each category implementation, so we don't have to use
+ -all_load or -force_load to load object files from static libraries that only contain
+ categories and no classes.
+ See http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html for more info.
+
+ Shamelessly borrowed from Three20
+ */
+#define RK_FIX_CATEGORY_BUG(name) @interface RK_FIX_CATEGORY_BUG##name @end \
+@implementation RK_FIX_CATEGORY_BUG##name @end
+
+#endif
View
8 Examples/RKCatalog/RKCatalog.xcodeproj/project.pbxproj
@@ -297,7 +297,7 @@
2501DEAD13607B74003DE9E4 /* libRestKitXMLParserLibxml.a */,
2501DEAF13607B74003DE9E4 /* libRestKitCoreData.a */,
2501DEB113607B74003DE9E4 /* libRestKitThree20.a */,
- 2501DEB313607B74003DE9E4 /* UISpec.app */,
+ 2501DEB313607B74003DE9E4 /* RestKitSpecs.app */,
);
name = Products;
sourceTree = "<group>";
@@ -533,10 +533,10 @@
remoteRef = 2501DEB013607B74003DE9E4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
- 2501DEB313607B74003DE9E4 /* UISpec.app */ = {
+ 2501DEB313607B74003DE9E4 /* RestKitSpecs.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
- path = UISpec.app;
+ path = RestKitSpecs.app;
remoteRef = 2501DEB213607B74003DE9E4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
@@ -704,6 +704,7 @@
"\"$(SOURCE_ROOT)/../../Build/$(BUILD_STYLE)-$(PLATFORM_NAME)\"",
"\"$(SRCROOT)\"",
);
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -721,6 +722,7 @@
"\"$(SOURCE_ROOT)/../../Build/$(BUILD_STYLE)-$(PLATFORM_NAME)\"",
"\"$(SRCROOT)\"",
);
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
VALIDATE_PRODUCT = YES;
WRAPPER_EXTENSION = app;
View
16 Examples/RKDiscussionBoardExample/DiscussionBoard/DiscussionBoard.xcodeproj/project.pbxproj
@@ -1114,7 +1114,7 @@
25A7B1DB13421D28004816AA /* libRestKitXMLParserLibxml.a */,
A7A2D3B512D7822D00683D6F /* libRestKitCoreData.a */,
A7A2D3B712D7822D00683D6F /* libRestKitThree20.a */,
- A7A2D3B912D7822D00683D6F /* UISpec.app */,
+ A7A2D3B912D7822D00683D6F /* RestKitSpecs.app */,
);
name = Products;
sourceTree = "<group>";
@@ -1248,10 +1248,10 @@
remoteRef = A7A2D3B612D7822D00683D6F /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
- A7A2D3B912D7822D00683D6F /* UISpec.app */ = {
+ A7A2D3B912D7822D00683D6F /* RestKitSpecs.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
- path = UISpec.app;
+ path = RestKitSpecs.app;
remoteRef = A7A2D3B812D7822D00683D6F /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
@@ -1378,10 +1378,7 @@
"\"$(SRCROOT)/Libraries/three20\"",
"\"$(SRCROOT)\"",
);
- OTHER_LDFLAGS = (
- "-all_load",
- "-ObjC",
- );
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "Discussion Board";
VALIDATE_PRODUCT = YES;
};
@@ -1401,10 +1398,7 @@
../../../Build,
Libraries/three20/Build/Products/three20,
);
- OTHER_LDFLAGS = (
- "-all_load",
- "-ObjC",
- );
+ OTHER_LDFLAGS = "-ObjC";
SDKROOT = iphoneos;
};
name = Debug;
View
18 Examples/RKMacOSX/RKMacOSX.xcodeproj/project.pbxproj
@@ -232,7 +232,7 @@
25D63964135184F1000879B1 /* libRestKitXMLParserLibxml.a */,
25D63966135184F1000879B1 /* libRestKitCoreData.a */,
25D63968135184F1000879B1 /* libRestKitThree20.a */,
- 25D6396A135184F1000879B1 /* UISpec.app */,
+ 25D6396A135184F1000879B1 /* RestKitSpecs.app */,
);
name = Products;
sourceTree = "<group>";
@@ -367,10 +367,10 @@
remoteRef = 25D63967135184F1000879B1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
- 25D6396A135184F1000879B1 /* UISpec.app */ = {
+ 25D6396A135184F1000879B1 /* RestKitSpecs.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
- path = UISpec.app;
+ path = RestKitSpecs.app;
remoteRef = 25D63969135184F1000879B1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
@@ -459,10 +459,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.6;
ONLY_ACTIVE_ARCH = YES;
- OTHER_LDFLAGS = (
- "-ObjC",
- "-all_load",
- );
+ OTHER_LDFLAGS = "-ObjC";
SDKROOT = macosx;
};
name = Debug;
@@ -477,10 +474,7 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.6;
- OTHER_LDFLAGS = (
- "-ObjC",
- "-all_load",
- );
+ OTHER_LDFLAGS = "-ObjC";
SDKROOT = macosx;
};
name = Release;
@@ -499,6 +493,7 @@
"$(inherited)",
"\"$(SRCROOT)\"",
);
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -518,6 +513,7 @@
"$(inherited)",
"\"$(SRCROOT)\"",
);
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
View
16 Examples/RKTwitter/RKTwitter.xcodeproj/project.pbxproj
@@ -218,7 +218,7 @@
250AC4AE1358C79C006F084F /* libRestKitXMLParserLibxml.a */,
250AC4B01358C79C006F084F /* libRestKitCoreData.a */,
250AC4B21358C79C006F084F /* libRestKitThree20.a */,
- 250AC4B41358C79C006F084F /* UISpec.app */,
+ 250AC4B41358C79C006F084F /* RestKitSpecs.app */,
);
name = Products;
sourceTree = "<group>";
@@ -399,10 +399,10 @@
remoteRef = 250AC4B11358C79C006F084F /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
- 250AC4B41358C79C006F084F /* UISpec.app */ = {
+ 250AC4B41358C79C006F084F /* RestKitSpecs.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
- path = UISpec.app;
+ path = RestKitSpecs.app;
remoteRef = 250AC4B31358C79C006F084F /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
@@ -469,10 +469,7 @@
HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Build";
INFOPLIST_FILE = "Resources/RKTwitter-Info.plist";
LIBRARY_SEARCH_PATHS = "$(inherited)";
- OTHER_LDFLAGS = (
- "-all_load",
- "-ObjC",
- );
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RKTwitter;
};
name = Debug;
@@ -488,10 +485,7 @@
HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Build";
INFOPLIST_FILE = "Resources/RKTwitter-Info.plist";
LIBRARY_SEARCH_PATHS = "$(inherited)";
- OTHER_LDFLAGS = (
- "-all_load",
- "-ObjC",
- );
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RKTwitter;
VALIDATE_PRODUCT = YES;
};
View
26 Examples/RKTwitterCoreData/RKTwitterCoreData.xcodeproj/project.pbxproj
@@ -264,7 +264,7 @@
251E0D53134189230017A6DA /* libRestKitXMLParserLibxml.a */,
3F3CE2CF125B93780083FDCB /* libRestKitCoreData.a */,
2538E808123417E500ACB5D7 /* libRestKitThree20.a */,
- 2538E80A123417E500ACB5D7 /* UISpec.app */,
+ 2538E80A123417E500ACB5D7 /* RestKitSpecs.app */,
);
name = Products;
sourceTree = "<group>";
@@ -412,10 +412,10 @@
remoteRef = 2538E807123417E500ACB5D7 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
- 2538E80A123417E500ACB5D7 /* UISpec.app */ = {
+ 2538E80A123417E500ACB5D7 /* RestKitSpecs.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
- path = UISpec.app;
+ path = RestKitSpecs.app;
remoteRef = 2538E809123417E500ACB5D7 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
@@ -563,10 +563,7 @@
GCC_PREFIX_HEADER = RKTwitter_Prefix.pch;
HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Build";
INFOPLIST_FILE = "Resources/RKTwitter-Info.plist";
- OTHER_LDFLAGS = (
- "-all_load",
- "-ObjC",
- );
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RKTwitterCoreData;
};
name = Debug;
@@ -581,10 +578,7 @@
GCC_PREFIX_HEADER = RKTwitter_Prefix.pch;
HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Build";
INFOPLIST_FILE = "Resources/RKTwitter-Info.plist";
- OTHER_LDFLAGS = (
- "-all_load",
- "-ObjC",
- );
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RKTwitterCoreData;
VALIDATE_PRODUCT = YES;
};
@@ -603,10 +597,7 @@
GCC_PREPROCESSOR_DEFINITIONS = RESTKIT_GENERATE_SEED_DB;
HEADER_SEARCH_PATHS = ../../Build;
INFOPLIST_FILE = "Resources/RKTwitter-Info.plist";
- OTHER_LDFLAGS = (
- "-all_load",
- "-ObjC",
- );
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "Generate Seed Database";
};
name = Debug;
@@ -622,10 +613,7 @@
GCC_PREPROCESSOR_DEFINITIONS = RESTKIT_GENERATE_SEED_DB;
HEADER_SEARCH_PATHS = ../../Build;
INFOPLIST_FILE = "Resources/RKTwitter-Info.plist";
- OTHER_LDFLAGS = (
- "-all_load",
- "-ObjC",
- );
+ OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "Generate Seed Database";
VALIDATE_PRODUCT = YES;
};
View
6 README.md
@@ -69,7 +69,7 @@ Quick Start (aka TL;DR)
1. Add **Header Search Path** to the `"$(SOURCE_ROOT)/RestKit/Build"` directory. **DO NOT** check the `Recursive` checkbox.
1. Add **Library Search Path** to the `"$(SOURCE_ROOT)/RestKit/Build/$(BUILD_STYLE)-$(PLATFORM_NAME)"` directory.
**NOTE**: This is only necessary if you are **NOT** using DerivedData.
-1. Add **Other Linker Flags** for `-ObjC -all_load`
+1. Add **Other Linker Flags** for `-ObjC`
1. Open target settings editor for the target you want to link RestKit into
1. Add direct dependency on the **RestKit** aggregate target
1. Link against required frameworks:
@@ -104,7 +104,7 @@ To add RestKit to your project (you're using git, right?):
1. Switch to the 'Build' tab in your project inspector. Make sure that your **Configuration** pop-up menu reads **All Configurations** so that your changes will work for all build configurations.
1. Find the **Header Search Paths** setting. Double click and add a new entry. When RestKit is compiled, it will copy all relevant headers to the appropriate location under the /Build directory within the RestKit checkout. You need to add a path to the /Build directory of RestKit, relative to your project file. For example, if you checked the submodule out in the root directory of your project, your header path would be `"$(SOURCE_ROOT)/RestKit/Build"`.
1. Find the **Library Search Paths** setting. Double click and add a new entry. Add a search path to your RestKit build directory such as `"$(SOURCE_ROOT)/RestKit/Build/$(BUILD_STYLE)-$(PLATFORM_NAME)"`
-1. Now find the **Other Linker Flags** setting. Double click it and add entries for -all_load and -ObjC.
+1. Now find the **Other Linker Flags** setting. Double click it and add entries for -ObjC.
1. You may now close out the inspector window.
Xcode 4.x (Git Submodule)
@@ -119,7 +119,7 @@ Xcode 4.x (Git Submodule)
1. Find the **Header Search Paths** setting. Double click and add a new entry. Add a search path to the `"$(SOURCE_ROOT)/RestKit/Build"` directory you have added to your project. **DO NOT** check the `Recursive` checkbox.
1. Find the **Library Search Paths** setting. Double click and add a new entry. Add a search path to the `"$(SOURCE_ROOT)/RestKit/Build/$(BUILD_STYLE)-$(PLATFORM_NAME)"` directory you have added to your project.
**NOTE**: This is only necessary if you are **NOT** using DerivedData.
-1. Find the **Other Linker Flags** entry and double click it. Use the **+** button to add a new entry and enter `-ObjC -all_load`. Dismiss the editor with the **Done** button.
+1. Find the **Other Linker Flags** entry and double click it. Use the **+** button to add a new entry and enter `-ObjC`. Dismiss the editor with the **Done** button.
1. Locate the target you wish to add RestKit to in the **TARGETS** list in the middle of the editor pane. Select it to open the target settings editor in the right pane of the window.
1. Click the **Build Phases** tab along the top of the window to open the Build Phases editor.
1. Click the disclosure triangles next to the **Target Dependencies** and **Link Binary with Libraries** items.
View
31 RestKit.xcodeproj/project.pbxproj
@@ -140,6 +140,7 @@
257FB7091395DC44003A628E /* RKManagedObjectMappingOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 257FB7071395DC44003A628E /* RKManagedObjectMappingOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
257FB70A1395DC44003A628E /* RKManagedObjectMappingOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 257FB7081395DC44003A628E /* RKManagedObjectMappingOperation.m */; };
258E490113C51FE600C9C883 /* RKJSONParserJSONKitSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 258E490013C51FE600C9C883 /* RKJSONParserJSONKitSpec.m */; };
+ 258F846F1410574B007AABCD /* RKFixCategoryBug.h in Headers */ = {isa = PBXBuildFile; fileRef = 258F846E1410574B007AABCD /* RKFixCategoryBug.h */; settings = {ATTRIBUTES = (Private, ); }; };
259050F413F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 259050F213F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.h */; settings = {ATTRIBUTES = (Public, ); }; };
259050F513F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.m in Sources */ = {isa = PBXBuildFile; fileRef = 259050F313F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.m */; };
2590E67F125235C200531FA8 /* JSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 2590E674125235C200531FA8 /* JSON.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -203,8 +204,6 @@
25952F0F136F8F7700D04F93 /* users.json in Resources */ = {isa = PBXBuildFile; fileRef = 25952F0C136F8F7700D04F93 /* users.json */; };
25952F12136F97B300D04F93 /* RKObjectSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 25952F10136F97B300D04F93 /* RKObjectSerializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
25952F13136F97B300D04F93 /* RKObjectSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 25952F11136F97B300D04F93 /* RKObjectSerializer.m */; };
- 25952FDD1370959900D04F93 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 25952FD81370959900D04F93 /* LICENSE.txt */; };
- 25952FDF1370959900D04F93 /* README.markdown in Resources */ = {isa = PBXBuildFile; fileRef = 25952FDC1370959900D04F93 /* README.markdown */; };
259562E4126D3B36004BAC4C /* RKObjectRouter.h in Headers */ = {isa = PBXBuildFile; fileRef = 259562E2126D3B36004BAC4C /* RKObjectRouter.h */; settings = {ATTRIBUTES = (Public, ); }; };
259562E5126D3B36004BAC4C /* RKObjectRouter.m in Sources */ = {isa = PBXBuildFile; fileRef = 259562E3126D3B36004BAC4C /* RKObjectRouter.m */; };
25956983126DF1AE004BAC4C /* libRestKitCoreData.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 253A081412551D5300976E89 /* libRestKitCoreData.a */; };
@@ -551,6 +550,7 @@
257FB70C1395DEB5003A628E /* RKManagedObjectMappingOperationSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectMappingOperationSpec.m; sourceTree = "<group>"; };
258C65EF133C317A004388A4 /* CopyHeadersToLegacyBuildDir.command */ = {isa = PBXFileReference; lastKnownFileType = text; path = CopyHeadersToLegacyBuildDir.command; sourceTree = "<group>"; };
258E490013C51FE600C9C883 /* RKJSONParserJSONKitSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKJSONParserJSONKitSpec.m; sourceTree = "<group>"; };
+ 258F846E1410574B007AABCD /* RKFixCategoryBug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKFixCategoryBug.h; sourceTree = "<group>"; };
259050F213F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RKObjectPropertyInspector+CoreData.h"; sourceTree = "<group>"; };
259050F313F8BDEB00694498 /* RKObjectPropertyInspector+CoreData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RKObjectPropertyInspector+CoreData.m"; sourceTree = "<group>"; };
2590E64F125231F600531FA8 /* libRestKitJSONParserYAJL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRestKitJSONParserYAJL.a; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -628,11 +628,6 @@
25952F0C136F8F7700D04F93 /* users.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = users.json; sourceTree = "<group>"; };
25952F10136F97B300D04F93 /* RKObjectSerializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectSerializer.h; sourceTree = "<group>"; };
25952F11136F97B300D04F93 /* RKObjectSerializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectSerializer.m; sourceTree = "<group>"; };
- 25952FD81370959900D04F93 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = "<group>"; };
- 25952FD91370959900D04F93 /* LoggerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoggerClient.h; sourceTree = "<group>"; };
- 25952FDA1370959900D04F93 /* LoggerClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoggerClient.m; sourceTree = "<group>"; };
- 25952FDB1370959900D04F93 /* LoggerCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoggerCommon.h; sourceTree = "<group>"; };
- 25952FDC1370959900D04F93 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.markdown; sourceTree = "<group>"; };
259562E2126D3B36004BAC4C /* RKObjectRouter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectRouter.h; sourceTree = "<group>"; };
259562E3126D3B36004BAC4C /* RKObjectRouter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectRouter.m; sourceTree = "<group>"; };
259BEF5013C3B12B00487F66 /* RKObjectMappingResultSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMappingResultSpec.m; sourceTree = "<group>"; };
@@ -1130,6 +1125,7 @@
253A09F512552BDC00976E89 /* Support.h */,
251939B213A94B5F0073A39B /* NSString+RestKit.h */,
251939B313A94B5F0073A39B /* NSString+RestKit.m */,
+ 258F846E1410574B007AABCD /* RKFixCategoryBug.h */,
);
path = Support;
sourceTree = "<group>";
@@ -1215,7 +1211,6 @@
isa = PBXGroup;
children = (
250D5BD913A0698100471F0E /* LibComponentLogging */,
- 25952FD71370959900D04F93 /* NSLogger */,
20808DB713DE8C7C000A156A /* NXJSON */,
73057FC61331AA28001908EE /* JSONKit */,
2590E69A1252372800531FA8 /* YAJL */,
@@ -1400,19 +1395,6 @@
path = humans;
sourceTree = "<group>";
};
- 25952FD71370959900D04F93 /* NSLogger */ = {
- isa = PBXGroup;
- children = (
- 25952FD81370959900D04F93 /* LICENSE.txt */,
- 25952FD91370959900D04F93 /* LoggerClient.h */,
- 25952FDA1370959900D04F93 /* LoggerClient.m */,
- 25952FDB1370959900D04F93 /* LoggerCommon.h */,
- 25952FDC1370959900D04F93 /* README.markdown */,
- );
- name = NSLogger;
- path = Vendor/NSLogger;
- sourceTree = "<group>";
- };
259D510D1328547000897272 /* CoreData */ = {
isa = PBXGroup;
children = (
@@ -1645,6 +1627,7 @@
250D5C0213A069EA00471F0E /* lcl_config_extensions.h in Headers */,
250D5C0413A06A4D00471F0E /* lcl_config_logger.h in Headers */,
251939B613A94B670073A39B /* NSString+RestKit.h in Headers */,
+ 258F846F1410574B007AABCD /* RKFixCategoryBug.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2001,8 +1984,6 @@
25952F0D136F8F7700D04F93 /* nested_user.json in Resources */,
25952F0E136F8F7700D04F93 /* user.json in Resources */,
25952F0F136F8F7700D04F93 /* users.json in Resources */,
- 25952FDD1370959900D04F93 /* LICENSE.txt in Resources */,
- 25952FDF1370959900D04F93 /* README.markdown in Resources */,
251939E913AABED40073A39B /* DynamicKeys.json in Resources */,
251939EA13AABED40073A39B /* error.json in Resources */,
251939EB13AABED40073A39B /* errors.json in Resources */,
@@ -2706,7 +2687,6 @@
"-force_load",
"$(PROJECT_DIR)/Specs/Runner/OCMock/libOCMock.a",
"-ObjC",
- "-all_load",
"-lstdc++",
"-framework",
SenTestingKit,
@@ -3059,7 +3039,6 @@
"-force_load",
"$(PROJECT_DIR)/Specs/Runner/OCMock/libOCMock.a",
"-ObjC",
- "-all_load",
"-lstdc++",
"-framework",
SenTestingKit,
@@ -3263,7 +3242,6 @@
"-force_load",
"$(PROJECT_DIR)/Specs/Runner/OCMock/libOCMock.a",
"-ObjC",
- "-all_load",
"-lstdc++",
"-framework",
SenTestingKit,
@@ -3309,7 +3287,6 @@
"-force_load",
"$(PROJECT_DIR)/Specs/Runner/OCMock/libOCMock.a",
"-ObjC",
- "-all_load",
"-lstdc++",
"-framework",
SenTestingKit,
View
23 Vendor/NSLogger/LICENSE.txt
@@ -1,23 +0,0 @@
-BSD license follows (http://www.opensource.org/licenses/bsd-license.php)
-
-Copyright (c) 2010, Florent Pillet All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification, are
-permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list of
-conditions and the following disclaimer. Redistributions in binary form must
-reproduce the above copyright notice, this list of conditions and the following
-disclaimer in the documentation and/or other materials provided with the
-distribution. Neither the name of Florent Pillet nor the names of its
-contributors may be used to endorse or promote products derived from this software
-without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
-HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
227 Vendor/NSLogger/LoggerClient.h
@@ -1,227 +0,0 @@
-/*
- * LoggerClient.h
- *
- * version 1.0b10 2011-02-18
- *
- * Part of NSLogger (client side)
- * https://github.com/fpillet/NSLogger
- *
- * BSD license follows (http://www.opensource.org/licenses/bsd-license.php)
- *
- * Copyright (c) 2010-2011 Florent Pillet All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer. Redistributions in
- * binary form must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution. Neither the name of Florent
- * Pillet nor the names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior written
- * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
- * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-#import <unistd.h>
-#import <pthread.h>
-#import <libkern/OSAtomic.h>
-#import <Foundation/Foundation.h>
-#import <CoreFoundation/CoreFoundation.h>
-#import <SystemConfiguration/SystemConfiguration.h>
-#if !TARGET_OS_IPHONE
-#import <CoreServices/CoreServices.h>
-#endif
-
-// This define is here so that user application can test whether NSLogger Client is
-// being included in the project, and potentially configure their macros accordingly
-#define NSLOGGER_WAS_HERE 1
-
-// Set this to 0 if you absolutely NOT want any access to Cocoa (Objective-C, NS* calls)
-// We need a couple ones to reliably obtain the thread number and device information
-// Note that since we need NSAutoreleasePool when using Cocoa in the logger's worker thread,
-// we need to put Cocoa in multithreading mode. Also, ALLOW_COCOA_USE allows the client code
-// to use NSLog()-style message formatting (less verbose than CFShow()-style) through the
-// use of -[NSString stringWithFormat:arguments:]
-#define ALLOW_COCOA_USE 1
-
-/* -----------------------------------------------------------------
- * Logger option flags & default options
- * -----------------------------------------------------------------
- */
-enum {
- kLoggerOption_LogToConsole = 0x01,
- kLoggerOption_BufferLogsUntilConnection = 0x02,
- kLoggerOption_BrowseBonjour = 0x04,
- kLoggerOption_BrowseOnlyLocalDomain = 0x08,
- kLoggerOption_UseSSL = 0x10
-};
-
-#define LOGGER_DEFAULT_OPTIONS (kLoggerOption_BufferLogsUntilConnection | \
- kLoggerOption_BrowseBonjour | \
- kLoggerOption_BrowseOnlyLocalDomain | \
- kLoggerOption_UseSSL)
-
-/* -----------------------------------------------------------------
- * Structure defining a Logger
- * -----------------------------------------------------------------
- */
-typedef struct
-{
- CFStringRef bufferFile; // If non-NULL, all buffering is done to the specified file instead of in-memory
- CFStringRef host; // Viewer host to connect to (instead of using Bonjour)
- UInt32 port; // port on the viewer host
-
- CFMutableArrayRef bonjourServiceBrowsers; // Active service browsers
- CFMutableArrayRef bonjourServices; // Services being tried
- CFNetServiceBrowserRef bonjourDomainBrowser; // Domain browser
-
- CFMutableArrayRef logQueue; // Message queue
- pthread_mutex_t logQueueMutex;
- pthread_cond_t logQueueEmpty;
-
- pthread_t workerThread; // The worker thread responsible for Bonjour resolution, connection and logs transmission
- CFRunLoopSourceRef messagePushedSource; // A message source that fires on the worker thread when messages are available for send
- CFRunLoopSourceRef bufferFileChangedSource; // A message source that fires on the worker thread when the buffer file configuration changes
-
- CFWriteStreamRef logStream; // The connected stream we're writing to
- CFWriteStreamRef bufferWriteStream; // If bufferFile not NULL and we're not connected, points to a stream for writing log data
- CFReadStreamRef bufferReadStream; // If bufferFile not NULL, points to a read stream that will be emptied prior to sending the rest of in-memory messages
-
- SCNetworkReachabilityRef reachability; // The reachability object we use to determine when the target host becomes reachable
- CFRunLoopTimerRef checkHostTimer; // A timer to regularly check connection to the defined host, along with reachability for added reliability
-
- uint8_t *sendBuffer; // data waiting to be sent
- NSUInteger sendBufferSize;
- NSUInteger sendBufferUsed; // number of bytes of the send buffer currently in use
- NSUInteger sendBufferOffset; // offset in sendBuffer to start sending at
-
- int32_t messageSeq; // sequential message number (added to each message sent)
-
- // settings
- uint32_t options; // Flags, see enum above
- CFStringRef bonjourServiceType; // leave NULL to use the default
- CFStringRef bonjourServiceName; // leave NULL to use the first one available
-
- // internal state
- BOOL connected; // Set to YES once the write stream declares the connection open
- volatile BOOL quit; // Set to YES to terminate the logger worker thread's runloop
- BOOL incompleteSendOfFirstItem; // set to YES if we are sending the first item in the queue and it's bigger than what the buffer can hold
-} Logger;
-
-
-/* -----------------------------------------------------------------
- * LOGGING FUNCTIONS
- * -----------------------------------------------------------------
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Functions to set and get the default logger
-extern void LoggerSetDefaultLogger(Logger *aLogger);
-extern Logger *LoggerGetDefaultLogger();
-
-// Initialize a new logger, set as default logger if this is the first one
-// Options default to:
-// - logging to console = NO
-// - buffer until connection = YES
-// - browse Bonjour = YES
-// - browse only locally on Bonjour = YES
-extern Logger* LoggerInit();
-
-// Set logger options if you don't want the default options (see above)
-extern void LoggerSetOptions(Logger *logger, uint32_t options);
-
-// Set Bonjour logging names, so you can force the logger to use a specific service type
-// or direct logs to the machine on your network which publishes a specific name
-extern void LoggerSetupBonjour(Logger *logger, CFStringRef bonjourServiceType, CFStringRef bonjourServiceName);
-
-// Directly set the viewer host (hostname or IP address) and port we want to connect to. If set, LoggerStart() will
-// try to connect there first before trying Bonjour
-extern void LoggerSetViewerHost(Logger *logger, CFStringRef hostName, UInt32 port);
-
-
-// Configure the logger to use a local file for buffering, instead of memory.
-// - If you initially set a buffer file after logging started but while a logger connection
-// has not been acquired, the contents of the log queue will be written to the buffer file
-// the next time a logging function is called, or when LoggerStop() is called.
-// - If you want to change the buffering file after logging started, you should first
-// call LoggerStop() the call LoggerSetBufferFile(). Note that all logs stored in the previous
-// buffer file WON'T be transferred to the new file in this case.
-extern void LoggerSetBufferFile(Logger *logger, CFStringRef absolutePath);
-
-// Activate the logger, try connecting
-extern void LoggerStart(Logger *logger);
-
-//extern void LoggerConnectToHost(CFDataRef address, int port);
-
-// Deactivate and free the logger.
-extern void LoggerStop(Logger *logger);
-
-// Pause the current thread until all messages from the logger have been transmitted
-// this is useful to use before an assert() aborts your program. If waitForConnection is YES,
-// LoggerFlush() will block even if the client is not currently connected to the desktop
-// viewer. You should be using NO most of the time, but in some cases it can be useful.
-extern void LoggerFlush(Logger *logger, BOOL waitForConnection);
-
-/* Logging functions. Each function exists in four versions:
- *
- * - one without a Logger instance (uses default logger) and without filename/line/function (no F suffix)
- * - one without a Logger instance but with filename/line/function (F suffix)
- * - one with a Logger instance (use a specific Logger) and without filename/line/function (no F suffix)
- * - one with a Logger instance (use a specific Logger) and with filename/line/function (F suffix)
- *
- * The exception being the single LogMessageCompat() function which is designed to be a drop-in replacement for NSLog()
- *
- */
-
-// Log a message, calling format compatible with NSLog
-extern void LogMessageCompat(NSString *format, ...);
-
-// Log a message. domain can be nil if default domain.
-extern void LogMessage(NSString *domain, int level, NSString *format, ...);
-extern void LogMessageF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, ...);
-extern void LogMessageTo(Logger *logger, NSString *domain, int level, NSString *format, ...);
-extern void LogMessageToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, ...);
-
-// Log a message. domain can be nil if default domain (versions with va_list format args instead of ...)
-extern void LogMessage_va(NSString *domain, int level, NSString *format, va_list args);
-extern void LogMessageF_va(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, va_list args);
-extern void LogMessageTo_va(Logger *logger, NSString *domain, int level, NSString *format, va_list args);
-extern void LogMessageToF_va(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, va_list args);
-
-// Send binary data to remote logger
-extern void LogData(NSString *domain, int level, NSData *data);
-extern void LogDataF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSData *data);
-extern void LogDataTo(Logger *logger, NSString *domain, int level, NSData *data);
-extern void LogDataToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSData *data);
-
-// Send image data to remote logger
-extern void LogImageData(NSString *domain, int level, int width, int height, NSData *data);
-extern void LogImageDataF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, int width, int height, NSData *data);
-extern void LogImageDataTo(Logger *logger, NSString *domain, int level, int width, int height, NSData *data);
-extern void LogImageDataToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, int width, int height, NSData *data);
-
-// Mark the start of a block. This allows the remote logger to group blocks together
-extern void LogStartBlock(NSString *format, ...);
-extern void LogStartBlockTo(Logger *logger, NSString *format, ...);
-
-// Mark the end of a block
-extern void LogEndBlock();
-extern void LogEndBlockTo(Logger *logger);
-
-#ifdef __cplusplus
-};
-#endif
View
2,193 Vendor/NSLogger/LoggerClient.m
@@ -1,2193 +0,0 @@
-/*
- * LoggerClient.m
- *
- * version 1.0b10 2011-02-18
- *
- * Main implementation of the NSLogger client side code
- * Part of NSLogger (client side)
- * https://github.com/fpillet/NSLogger
- *
- * BSD license follows (http://www.opensource.org/licenses/bsd-license.php)
- *
- * Copyright (c) 2010-2011 Florent Pillet All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer. Redistributions in
- * binary form must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution. Neither the name of Florent
- * Pillet nor the names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior written
- * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
- * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-// Defined here to enable building into static lib
-#define ALLOW_COCOA_USE 1
-
-#import <sys/time.h>
-#if !TARGET_OS_IPHONE
- #import <sys/types.h>
- #import <sys/sysctl.h>
- #import <dlfcn.h>
-#elif ALLOW_COCOA_USE
- #import <UIKit/UIKit.h>
-#endif
-#import <fcntl.h>
-
-#import "LoggerClient.h"
-#import "LoggerCommon.h"
-
-/* --------------------------------------------------------------------------------
- * IMPLEMENTATION NOTES:
- *
- * The logger runs in a separate thread. It is written
- * in straight C for maximum compatibility with all runtime environments
- * (does not use the Objective-C runtime, only uses unix and CoreFoundation
- * calls, except for get the thread name and device information, but these
- * can be disabled by setting ALLOW_COCOA_USE to 0).
- *
- * It is suitable for use in both Cocoa and low-level code. It does not activate
- * Cocoa multi-threading (no call to [NSThread detachNewThread...]). You can start
- * logging very early (as soon as your code starts running), logs will be
- * buffered and sent to the log viewer as soon as a connection is acquired.
- * This makes the logger suitable for use in conditions where you usually
- * don't have a connection to a remote machine yet (early wakeup, network
- * down, etc).
- *
- * When you call one of the public logging functions, the logger is designed
- * to return to your application as fast as possible. It enqueues logs to
- * send for processing by its own thread, while your application keeps running.
- *
- * The logger does buffer logs while not connected to a desktop
- * logger. It uses Bonjour to find a logger on the local network, and can
- * optionally connect to a remote logger identified by an IP address / port
- * or a Host Name / port.
- *
- * The logger can optionally output its log to the console, like NSLog().
- *
- * The logger can optionally buffer its logs to a file for which you specify the
- * full path. Upon connection to the desktop viewer, the file contents are
- * transmitted to the viewer prior to sending new logs. When the whole file
- * content has been transmitted, it is emptied.
- *
- * Multiple loggers can coexist at the same time. You can perfectly use a
- * logger for your debug traces, and another that connects remotely to help
- * diagnostic issues while the application runs on your user's device.
- *
- * Using the logger's flexible packet format, you can customize logging by
- * creating your own log types, and customize the desktop viewer to display
- * runtime information panels for your application.
- * --------------------------------------------------------------------------------
- */
-
-/* Logger internal debug flags */
-// Set to 0 to disable internal debug completely
-// Set to 1 to activate console logs when running the logger itself
-// Set to 2 to see every logging call issued by the app, too
-#define LOGGER_DEBUG 0
-#ifdef NSLog
- #undef NSLog
-#endif
-
-// Internal debugging stuff for the logger itself
-#if LOGGER_DEBUG
- #define LOGGERDBG LoggerDbg
- #if LOGGER_DEBUG > 1
- #define LOGGERDBG2 LoggerDbg
- #else
- #define LOGGERDBG2(format, ...) do{}while(0)
- #endif
- // Internal logging function prototype
- static void LoggerDbg(CFStringRef format, ...);
-#else
- #define LOGGERDBG(format, ...) do{}while(0)
- #define LOGGERDBG2(format, ...) do{}while(0)
-#endif
-
-/* Local prototypes */
-static void* LoggerWorkerThread(Logger *logger);
-static void LoggerWriteMoreData(Logger *logger);
-static void LoggerPushMessageToQueue(Logger *logger, CFDataRef message);
-
-// Bonjour management
-static void LoggerStartBonjourBrowsing(Logger *logger);
-static void LoggerStopBonjourBrowsing(Logger *logger);
-static BOOL LoggerBrowseBonjourForServices(Logger *logger, CFStringRef domainName);
-static void LoggerServiceBrowserCallBack(CFNetServiceBrowserRef browser, CFOptionFlags flags, CFTypeRef domainOrService, CFStreamError* error, void *info);
-
-// Reachability and reconnect timer
-static void LoggerStartReachabilityChecking(Logger *logger);
-static void LoggerStopReachabilityChecking(Logger *logger);
-static void LoggerReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info);
-static void LoggerTimedReconnectCallback(CFRunLoopTimerRef timer, void *info);
-
-// Connection & stream management
-static void LoggerTryConnect(Logger *logger);
-static void LoggerWriteStreamCallback(CFWriteStreamRef ws, CFStreamEventType event, void* info);
-#if LOGGER_DEBUG
-static void LoggerReadStreamCallback(CFReadStreamRef ws, CFStreamEventType event, void* info);
-#endif
-
-// File buffering
-static void LoggerCreateBufferWriteStream(Logger *logger);
-static void LoggerCreateBufferReadStream(Logger *logger);
-static void LoggerEmptyBufferFile(Logger *logger);
-static void LoggerFileBufferingOptionsChanged(Logger *logger);
-static void LoggerFlushQueueToBufferStream(Logger *logger, BOOL firstEntryIsClientInfo);
-
-// Encoding functions
-static void LoggerPushClientInfoToFrontOfQueue(Logger *logger);
-static void LoggerMessageAddTimestampAndThreadID(CFMutableDataRef encoder);
-static void LogDataInternal(Logger *logger, NSString *domain, int level, NSData *data, int binaryOrImageType);
-
-static CFMutableDataRef LoggerMessageCreate();
-static void LoggerMessageUpdateDataHeader(CFMutableDataRef data);
-static void LoggerMessageAddInt16(CFMutableDataRef data, int16_t anInt, int key);
-static void LoggerMessageAddInt32(CFMutableDataRef data, int32_t anInt, int key);
-static void LoggerMessageAddInt64(CFMutableDataRef data, int64_t anInt, int key);
-static void LoggerMessageAddString(CFMutableDataRef data, CFStringRef aString, int key);
-static void LoggerMessageAddData(CFMutableDataRef data, CFDataRef theData, int key, int partType);
-static uint32_t LoggerMessageGetSeq(CFDataRef message);
-
-/* Static objects */
-static Logger* volatile sDefaultLogger = NULL;
-static pthread_mutex_t sDefaultLoggerMutex = PTHREAD_MUTEX_INITIALIZER;
-
-// -----------------------------------------------------------------------------
-#pragma mark -
-#pragma mark Default logger
-// -----------------------------------------------------------------------------
-void LoggerSetDefautLogger(Logger *defaultLogger)
-{
- pthread_mutex_lock(&sDefaultLoggerMutex);
- sDefaultLogger = defaultLogger;
- pthread_mutex_unlock(&sDefaultLoggerMutex);
-}
-
-Logger *LoggerGetDefaultLogger()
-{
- if (sDefaultLogger == NULL)
- {
- pthread_mutex_lock(&sDefaultLoggerMutex);
- Logger *logger = LoggerInit();
- if (sDefaultLogger == NULL)
- {
- sDefaultLogger = logger;
- logger = NULL;
- }
- pthread_mutex_unlock(&sDefaultLoggerMutex);
- if (logger != NULL)
- LoggerStop(logger);
- }
- return sDefaultLogger;
-}
-
-// -----------------------------------------------------------------------------
-#pragma mark -
-#pragma mark Initialization and setup
-// -----------------------------------------------------------------------------
-Logger *LoggerInit()
-{
- LOGGERDBG(CFSTR("LoggerInit defaultLogger=%p"), sDefaultLogger);
-
- Logger *logger = (Logger *)malloc(sizeof(Logger));
- bzero(logger, sizeof(Logger));
-
- logger->logQueue = CFArrayCreateMutable(NULL, 32, &kCFTypeArrayCallBacks);
- pthread_mutex_init(&logger->logQueueMutex, NULL);
- pthread_cond_init(&logger->logQueueEmpty, NULL);
-
- logger->bonjourServiceBrowsers = CFArrayCreateMutable(NULL, 4, &kCFTypeArrayCallBacks);
- logger->bonjourServices = CFArrayCreateMutable(NULL, 4, &kCFTypeArrayCallBacks);
-
- // for now we don't grow the send buffer, just use one page of memory which should be enouh
- // (bigger messages will be sent separately)
- logger->sendBuffer = (uint8_t *)malloc(4096);
- logger->sendBufferSize = 4096;
-
- logger->options = LOGGER_DEFAULT_OPTIONS;
-
- logger->quit = NO;
-
- // Set this logger as the default logger is none exist already
- if (!pthread_mutex_trylock(&sDefaultLoggerMutex))
- {
- if (sDefaultLogger == NULL)
- sDefaultLogger = logger;
- pthread_mutex_unlock(&sDefaultLoggerMutex);
- }
-
- return logger;
-}
-
-void LoggerSetOptions(Logger *logger, uint32_t options)
-{
- LOGGERDBG(CFSTR("LoggerSetOptions options=0x%08lx"), options);
-
- if (logger == NULL)
- logger = LoggerGetDefaultLogger();
- if (logger != NULL)
- logger->options = options;
-}
-
-void LoggerSetupBonjour(Logger *logger, CFStringRef bonjourServiceType, CFStringRef bonjourServiceName)
-{
- LOGGERDBG(CFSTR("LoggerSetupBonjour serviceType=%@ serviceName=%@"), bonjourServiceType, bonjourServiceName);
-
- if (logger == NULL)
- logger = LoggerGetDefaultLogger();
- if (logger != NULL)
- {
- if (bonjourServiceType != NULL)
- CFRetain(bonjourServiceType);
- if (bonjourServiceName != NULL)
- CFRetain(bonjourServiceName);
- if (logger->bonjourServiceType != NULL)
- CFRelease(logger->bonjourServiceType);
- if (logger->bonjourServiceName != NULL)
- CFRelease(logger->bonjourServiceName);
- logger->bonjourServiceType = bonjourServiceType;
- logger->bonjourServiceName = bonjourServiceName;
- }
-}
-
-void LoggerSetViewerHost(Logger *logger, CFStringRef hostName, UInt32 port)
-{
- if (logger == NULL)
- logger = LoggerGetDefaultLogger();
- if (logger == NULL)
- return;
-
- if (logger->host != NULL)
- {
- CFRelease(logger->host);
- logger->host = NULL;
- }
- if (hostName != NULL)
- {
- logger->host = CFStringCreateCopy(NULL, hostName);
- logger->port = port;
- }
-}
-
-void LoggerSetBufferFile(Logger *logger, CFStringRef absolutePath)
-{
- if (logger == NULL)
- {
- logger = LoggerGetDefaultLogger();
- if (logger == NULL)
- return;
- }
-
- BOOL change = ((logger->bufferFile != NULL && absolutePath == NULL) ||
- (logger->bufferFile == NULL && absolutePath != NULL) ||
- (logger->bufferFile != NULL && absolutePath != NULL && CFStringCompare(logger->bufferFile, absolutePath, 0) != kCFCompareEqualTo));
- if (change)
- {
- if (logger->bufferFile != NULL)
- {
- CFRelease(logger->bufferFile);
- logger->bufferFile = NULL;
- }
- if (absolutePath != NULL)
- logger->bufferFile = CFStringCreateCopy(NULL, absolutePath);
- if (logger->bufferFileChangedSource != NULL)
- CFRunLoopSourceSignal(logger->bufferFileChangedSource);
- }
-}
-
-void LoggerStart(Logger *logger)
-{
- // will do nothing if logger is already started
- if (logger == NULL)
- logger = LoggerGetDefaultLogger();
-
- if (logger->workerThread == NULL)
- {
- // Start the work thread which performs the Bonjour search,
- // connects to the logging service and forwards the logs
- LOGGERDBG(CFSTR("LoggerStart logger=%p"), logger);
- pthread_create(&logger->workerThread, NULL, (void *(*)(void *))&LoggerWorkerThread, logger);
- }
-}
-
-void LoggerStop(Logger *logger)
-{
- LOGGERDBG(CFSTR("LoggerStop"));
-
- pthread_mutex_lock(&sDefaultLoggerMutex);
- if (logger == NULL || logger == sDefaultLogger)
- {
- logger = sDefaultLogger;
- sDefaultLogger = NULL;
- }
- pthread_mutex_unlock(&sDefaultLoggerMutex);
-
- if (logger != NULL)
- {
- if (logger->workerThread != NULL)
- {
- logger->quit = YES;
- pthread_join(logger->workerThread, NULL);
- }
-
- CFRelease(logger->bonjourServiceBrowsers);
- CFRelease(logger->bonjourServices);
- free(logger->sendBuffer);
- if (logger->host != NULL)
- CFRelease(logger->host);
- if (logger->bufferFile != NULL)
- CFRelease(logger->bufferFile);
- if (logger->bonjourServiceType != NULL)
- CFRelease(logger->bonjourServiceType);
- if (logger->bonjourServiceName != NULL)
- CFRelease(logger->bonjourServiceName);
-
- // to make sure potential errors are catched, set the whole structure
- // to a value that will make code crash if it tries using pointers to it.
- memset(logger, 0x55, sizeof(logger));
-
- free(logger);
- }
-}
-
-void LoggerFlush(Logger *logger, BOOL waitForConnection)
-{
- // Special case: if nothing has ever been logged, don't bother
- if (logger == NULL && sDefaultLogger == NULL)
- return;
- if (logger == NULL)
- logger = LoggerGetDefaultLogger();
- if (logger != NULL &&
- pthread_self() != logger->workerThread &&
- (logger->connected || logger->bufferFile != NULL || waitForConnection))
- {
- pthread_mutex_lock(&logger->logQueueMutex);
- if (CFArrayGetCount(logger->logQueue) > 0)
- pthread_cond_wait(&logger->logQueueEmpty, &logger->logQueueMutex);
- pthread_mutex_unlock(&logger->logQueueMutex);
- }
-}
-
-static void LoggerDbg(CFStringRef format, ...)
-{
- // Internal debugging function
- // (what do you think, that we use the Logger to debug itself ??)
- if (format != NULL)
- {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- va_list args;
- va_start(args, format);
- CFStringRef s = CFStringCreateWithFormatAndArguments(NULL, NULL, (CFStringRef)format, args);
- va_end(args);
- if (s != NULL)
- {
- CFShow(s);
- CFRelease(s);
- }
- [pool drain];
- }
-}
-
-// -----------------------------------------------------------------------------
-#pragma mark -
-#pragma mark Main processing
-// -----------------------------------------------------------------------------
-static void *LoggerWorkerThread(Logger *logger)
-{
- LOGGERDBG(CFSTR("Start LoggerWorkerThread"));
-
-#if !TARGET_OS_IPHONE
- // Register thread with Garbage Collector on Mac OS X if we're running an OS version that has GC
- void (*registerThreadWithCollector_fn)(void);
- registerThreadWithCollector_fn = (void(*)(void)) dlsym(RTLD_NEXT, "objc_registerThreadWithCollector");
- if (registerThreadWithCollector_fn)
- (*registerThreadWithCollector_fn)();
-#endif
-
- // Create and get the runLoop for this thread
- CFRunLoopRef runLoop = CFRunLoopGetCurrent();
-
- // Create the run loop source that signals when messages have been added to the runloop
- // this will directly trigger a WriteMoreData() call, which will or won't write depending
- // on whether we're connected and there's space available in the stream
- CFRunLoopSourceContext context;
- bzero(&context, sizeof(context));
- context.info = logger;
- context.perform = (void *)&LoggerWriteMoreData;
- logger->messagePushedSource = CFRunLoopSourceCreate(NULL, 0, &context);
- if (logger->messagePushedSource == NULL)
- {
- // Failing to create the runloop source for pushing messages is a major failure.
- // This NSLog is intentional. We WANT console output in this case
- NSLog(@"*** NSLogger: Worker thread failed creating runLoop source, switching to console logging.");
- logger->options |= kLoggerOption_LogToConsole;
- logger->workerThread = NULL;
- return NULL;
- }
- CFRunLoopAddSource(runLoop, logger->messagePushedSource, kCFRunLoopDefaultMode);
-
- // Create the buffering stream if needed
- if (logger->bufferFile != NULL)
- LoggerCreateBufferWriteStream(logger);
-
- // Create the runloop source that lets us know when file buffering options change
- context.perform = (void *)&LoggerFileBufferingOptionsChanged;
- logger->bufferFileChangedSource = CFRunLoopSourceCreate(NULL, 0, &context);
- if (logger->bufferFileChangedSource == NULL)
- {
- // This failure MUST be logged to console
- NSLog(@"*** NSLogger Warning: failed creating a runLoop source for file buffering options change.");
- }
- else
- CFRunLoopAddSource(runLoop, logger->bufferFileChangedSource, kCFRunLoopDefaultMode);
-
- // Start Bonjour browsing, wait for remote logging service to be found
- if (logger->host == NULL && (logger->options & kLoggerOption_BrowseBonjour))
- {
- LOGGERDBG(CFSTR("-> logger configured for Bonjour, no direct host set -- trying Bonjour first"));
- LoggerStartBonjourBrowsing(logger);
- }
- else if (logger->host != NULL)
- {
- LOGGERDBG(CFSTR("-> logger configured with direct host, trying it first"));
- LoggerTryConnect(logger);
- }
-
- // Run logging thread until LoggerStop() is called
- while (!logger->quit)
- {
- int result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, true);
- if (result == kCFRunLoopRunFinished || result == kCFRunLoopRunStopped)
- break;
-
- // Make sure we restart connection attempts if we get disconnected
- if (!logger->connected &&
- !CFArrayGetCount(logger->bonjourServices) &&
- !CFArrayGetCount(logger->bonjourServiceBrowsers) &&
- !CFArrayGetCount(logger->bonjourServices))
- {
- if (logger->options & kLoggerOption_BrowseBonjour)
- LoggerStartBonjourBrowsing(logger);
- else if (logger->host != NULL && logger->reachability == NULL && logger->checkHostTimer == NULL)
- LoggerTryConnect(logger);
- }
- }
-
- // Cleanup
- if (logger->options & kLoggerOption_BrowseBonjour)
- LoggerStopBonjourBrowsing(logger);
- LoggerStopReachabilityChecking(logger);
-
- if (logger->logStream != NULL)
- {
- CFWriteStreamSetClient(logger->logStream, 0, NULL, NULL);
- CFWriteStreamClose(logger->logStream);
- CFRelease(logger->logStream);
- logger->logStream = NULL;
- }
-
- if (logger->bufferWriteStream == NULL && logger->bufferFile != NULL)
- {
- // If there are messages in the queue and LoggerStop() was called and
- // a buffer file was set just before LoggerStop() was called, flush
- // the log queue to the buffer file
- pthread_mutex_lock(&logger->logQueueMutex);
- CFIndex outstandingMessages = CFArrayGetCount(logger->logQueue);
- pthread_mutex_unlock(&logger->logQueueMutex);
- if (outstandingMessages)
- LoggerCreateBufferWriteStream(logger);
- }
-
- if (logger->bufferWriteStream != NULL)
- {
- CFWriteStreamClose(logger->bufferWriteStream);
- CFRelease(logger->bufferWriteStream);
- logger->bufferWriteStream = NULL;
- }
-
- if (logger->messagePushedSource != NULL)
- {
- CFRunLoopSourceInvalidate(logger->messagePushedSource);
- CFRelease(logger->messagePushedSource);
- logger->messagePushedSource = NULL;
- }
-
- if (logger->bufferFileChangedSource != NULL)
- {
- CFRunLoopSourceInvalidate(logger->bufferFileChangedSource);
- CFRelease(logger->bufferFileChangedSource);
- logger->bufferFileChangedSource = NULL;
- }
-
- // if the client ever tries to log again against us, make sure that logs at least
- // go to console
- logger->options |= kLoggerOption_LogToConsole;
- logger->workerThread = NULL;
- return NULL;
-}
-
-static CFStringRef LoggerCreateStringRepresentationFromBinaryData(CFDataRef data)
-{
- CFMutableStringRef s = CFStringCreateMutable(NULL, 0);
- unsigned int offset = 0;
- unsigned int dataLen = (unsigned int)CFDataGetLength(data);
- char buffer[1+6+16*3+1+16+1+1+1];
- buffer[0] = '\0';
- const unsigned char *q = (unsigned char *)CFDataGetBytePtr(data);
- if (dataLen == 1)
- CFStringAppend(s, CFSTR("Raw data, 1 byte:\n"));
- else
- CFStringAppendFormat(s, NULL, CFSTR("Raw data, %u bytes:\n"), dataLen);
- while (dataLen)
- {
- int i, j, b = sprintf(buffer," %04x: ", offset);
- for (i=0; i < 16 && i < (int)dataLen; i++)
- sprintf(&buffer[b+3*i], "%02x ", (int)q[i]);
- for (j=i; j < 16; j++)
- strcat(buffer, " ");
-
- b = strlen(buffer);
- buffer[b++] = '\'';
- for (i=0; i < 16 && i < (int)dataLen; i++, q++)
- {
- if (*q >= 32 && *q < 128)
- buffer[b++] = *q;
- else
- buffer[b++] = ' ';
- }
- for (j=i; j < 16; j++)
- buffer[b++] = ' ';
- buffer[b++] = '\'';
- buffer[b++] = '\n';
- buffer[b] = 0;
-
- CFStringRef bufferStr = CFStringCreateWithBytesNoCopy(NULL, (const UInt8 *)buffer, strlen(buffer), kCFStringEncodingISOLatin1, false, kCFAllocatorNull);
- CFStringAppend(s, bufferStr);
- CFRelease(bufferStr);
-
- dataLen -= i;
- offset += i;
- }
- return s;
-}
-
-static void LoggerLogToConsole(CFDataRef data)
-{
- // Decode and log a message to the console. Doing this from the worker thread
- // allow us to serialize logging, which is a benefit that NSLog() doesn't have.
- // Only drawback is that we have to decode our own message, but that is a minor hassle.
-
- struct timeval timestamp;
- bzero(&timestamp, sizeof(timestamp));
- int type = LOGMSG_TYPE_LOG, contentsType = PART_TYPE_STRING;
- int imgWidth=0, imgHeight=0;
- CFStringRef message = NULL;
- CFStringRef thread = NULL;
-
- // decode message contents
- uint8_t *p = (uint8_t *)CFDataGetBytePtr(data) + 4;
- uint16_t partCount;
- memcpy(&partCount, p, 2);
- partCount = ntohs(partCount);
- p += 2;
- while (partCount--)
- {
- uint8_t partKey = *p++;
- uint8_t partType = *p++;
- uint32_t partSize;
- if (partType == PART_TYPE_INT16)
- partSize = 2;
- else if (partType == PART_TYPE_INT32)
- partSize = 4;
- else if (partType == PART_TYPE_INT64)
- partSize = 8;
- else
- {
- memcpy(&partSize, p, 4);
- p += 4;
- partSize = ntohl(partSize);
- }
- CFTypeRef part = NULL;
- uint32_t value32 = 0;
- uint64_t value64 = 0;
- if (partSize > 0)
- {
- if (partType == PART_TYPE_STRING)
- {
- // trim whitespace and newline at both ends of the string
- uint8_t *q = p;
- uint32_t l = partSize;
- while (l && (*q == ' ' || *q == '\t' || *q == '\n' || *q == '\r'))
- q++, l--;
- uint8_t *r = q + l - 1;
- while (l && (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r'))
- r--, l--;
- part = CFStringCreateWithBytesNoCopy(NULL, q, l, kCFStringEncodingUTF8, false, kCFAllocatorNull);
- }
- else if (partType == PART_TYPE_BINARY)
- {
- part = CFDataCreateWithBytesNoCopy(NULL, p, partSize, kCFAllocatorNull);
- }
- else if (partType == PART_TYPE_IMAGE)
- {
- // ignore image data, we can't log it to console
- }
- else if (partType == PART_TYPE_INT32)
- {
- memcpy(&value32, p, 4);
- value32 = ntohl(value32);
- }
- else if (partType == PART_TYPE_INT64)
- {
- memcpy(&value64, p, 8);
- value64 = CFSwapInt64BigToHost(value64);
- }
- p += partSize;
- }
- switch (partKey)
- {
- case PART_KEY_MESSAGE_TYPE:
- type = (int)value32;
- break;
- case PART_KEY_TIMESTAMP_S: // timestamp with seconds-level resolution
- timestamp.tv_sec = (partType == PART_TYPE_INT64) ? (__darwin_time_t)value64 : (__darwin_time_t)value32;
- break;
- case PART_KEY_TIMESTAMP_MS: // millisecond part of the timestamp (optional)
- timestamp.tv_usec = ((partType == PART_TYPE_INT64) ? (__darwin_suseconds_t)value64 : (__darwin_suseconds_t)value32) * 1000;
- break;
- case PART_KEY_TIMESTAMP_US: // microsecond part of the timestamp (optional)
- timestamp.tv_usec = (partType == PART_TYPE_INT64) ? (__darwin_suseconds_t)value64 : (__darwin_suseconds_t)value32;
- break;
- case PART_KEY_THREAD_ID:
- if (thread == NULL) // useless test, we know what we're doing but clang analyzer doesn't...
- {
- if (partType == PART_TYPE_INT32)
- thread = CFStringCreateWithFormat(NULL, NULL, CFSTR("thread 0x%08x"), value32);
- else if (partType == PART_TYPE_INT64)
- thread = CFStringCreateWithFormat(NULL, NULL, CFSTR("thread 0x%qx"), value64);
- else if (partType == PART_TYPE_STRING && part != NULL)
- thread = CFRetain(part);
- }
- break;
- case PART_KEY_MESSAGE:
- if (part != NULL)
- {
- if (partType == PART_TYPE_STRING)
- message = CFRetain(part);
- else if (partType == PART_TYPE_BINARY)
- message = LoggerCreateStringRepresentationFromBinaryData(part);
- }
- contentsType = partType;
- break;
- case PART_KEY_IMAGE_WIDTH:
- imgWidth = (partType == PART_TYPE_INT32 ? (int)value32 : (int)value64);
- break;
- case PART_KEY_IMAGE_HEIGHT:
- imgHeight = (partType == PART_TYPE_INT32 ? (int)value32 : (int)value64);
- break;
- default:
- break;
- }
- if (part != NULL)
- CFRelease(part);
- }
-
- // Prepare the final representation and log to console
- CFMutableStringRef s = CFStringCreateMutable(NULL, 0);
-
- char buf[32];
- struct tm t;
- gmtime_r(&timestamp.tv_sec, &t);
- strftime(buf, sizeof(buf)-1, "%T", &t);
- CFStringRef ts = CFStringCreateWithBytesNoCopy(NULL, (const UInt8 *)buf, strlen(buf), kCFStringEncodingASCII, false, kCFAllocatorNull);
- CFStringAppend(s, ts);
- CFRelease(ts);
-
- if (contentsType == PART_TYPE_IMAGE)
- message = CFStringCreateWithFormat(NULL, NULL, CFSTR("<image width=%d height=%d>"), imgWidth, imgHeight);
-
- char threadNamePadding[16];
- threadNamePadding[0] = 0;
- if (CFStringGetLength(thread) < 16)
- {
- int n = 16 - CFStringGetLength(thread);
- memset(threadNamePadding, ' ', n);
- threadNamePadding[n] = 0;
- }
- CFStringAppendFormat(s, NULL, CFSTR(".%04d %s%@ | %@"),
- (int)(timestamp.tv_usec / 1000),
- threadNamePadding, thread,
- message ? message : CFSTR(""));
-
- if (thread != NULL)
- CFRelease(thread);
- if (message)
- CFRelease(message);
-
- if (type == LOGMSG_TYPE_LOG)
- CFShow(s);
-
- CFRelease(s);
-}
-
-static void LoggerWriteMoreData(Logger *logger)
-{
- if (!logger->connected)
- {
- if (logger->options & kLoggerOption_LogToConsole)
- {
- pthread_mutex_lock(&logger->logQueueMutex);
- while (CFArrayGetCount(logger->logQueue))
- {
- LoggerLogToConsole((CFDataRef)CFArrayGetValueAtIndex(logger->logQueue, 0));
- CFArrayRemoveValueAtIndex(logger->logQueue, 0);
- }
- pthread_mutex_unlock(&logger->logQueueMutex);
- pthread_cond_broadcast(&logger->logQueueEmpty);
- }
- else if (logger->bufferWriteStream != NULL)
- {
- LoggerFlushQueueToBufferStream(logger, NO);
- }
- return;
- }
-
- if (CFWriteStreamCanAcceptBytes(logger->logStream))
- {
- // prepare archived data with log queue contents, unblock the queue as soon as possible
- CFMutableDataRef sendFirstItem = NULL;
- if (logger->sendBufferUsed == 0)
- {
- // pull more data from the log queue
- if (logger->bufferReadStream != NULL)
- {
- if (!CFReadStreamHasBytesAvailable(logger->bufferReadStream))
- {
- CFReadStreamClose(logger->bufferReadStream);
- CFRelease(logger->bufferReadStream);
- logger->bufferReadStream = NULL;
- LoggerEmptyBufferFile(logger);
- }
- else
- {
- logger->sendBufferUsed = CFReadStreamRead(logger->bufferReadStream, logger->sendBuffer, logger->sendBufferSize);
- }
- }
- else
- {
- pthread_mutex_lock(&logger->logQueueMutex);
- while (CFArrayGetCount(logger->logQueue))
- {
- CFDataRef d = (CFDataRef)CFArrayGetValueAtIndex(logger->logQueue, 0);
- CFIndex dsize = CFDataGetLength(d);
- if ((logger->sendBufferUsed + dsize) > logger->sendBufferSize)
- break;
- memcpy(logger->sendBuffer + logger->sendBufferUsed, CFDataGetBytePtr(d), dsize);
- logger->sendBufferUsed += dsize;
- CFArrayRemoveValueAtIndex(logger->logQueue, 0);
- logger->incompleteSendOfFirstItem = NO;
- }
- pthread_mutex_unlock(&logger->logQueueMutex);
- }
- if (logger->sendBufferUsed == 0)
- {
- // are we done yet?
- pthread_mutex_lock(&logger->logQueueMutex);
- if (CFArrayGetCount(logger->logQueue) == 0)
- {
- pthread_mutex_unlock(&logger->logQueueMutex);
- pthread_cond_broadcast(&logger->logQueueEmpty);
- return;
- }
-
- // first item is too big to fit in a single packet, send it separately
- sendFirstItem = (CFMutableDataRef)CFArrayGetValueAtIndex(logger->logQueue, 0);
- logger->incompleteSendOfFirstItem = YES;
- pthread_mutex_unlock(&logger->logQueueMutex);
- logger->sendBufferOffset = 0;
- }
- }
-
- // send data over the socket. We try hard to be failsafe and if we have to send
- // data in fragments, we make sure that in case a disconnect occurs we restart
- // sending the whole message(s)
- if (logger->sendBufferUsed != 0)
- {
- CFIndex written = CFWriteStreamWrite(logger->logStream,
- logger->sendBuffer + logger->sendBufferOffset,
- logger->sendBufferUsed - logger->sendBufferOffset);
- if (written < 0)
- {
- // We'll get an event if the stream closes on error. Don't discard the data,
- // it will be sent as soon as a connection is re-acquired.
- return;
- }
- if ((logger->sendBufferOffset + written) < logger->sendBufferUsed)
- {
- // everything couldn't be sent at once
- logger->sendBufferOffset += written;
- }
- else
- {
- logger->sendBufferUsed = 0;
- logger->sendBufferOffset = 0;
- }
- }
- else if (sendFirstItem)
- {
- CFIndex length = CFDataGetLength(sendFirstItem) - logger->sendBufferOffset;
- CFIndex written = CFWriteStreamWrite(logger->logStream,
- CFDataGetBytePtr(sendFirstItem) + logger->sendBufferOffset,
- length);
- if (written < 0)
- {
- // We'll get an event if the stream closes on error
- return;
- }
- if (written < length)
- {
- // The output pipe is full, and the first item has not been sent completely
- // We need to reduce the remaining data on the first item so it can be taken
- // care of at the next iteration. We take advantage of the fact that each item
- // in the queue is actually a mutable data block
- // @@@ NOTE: IF WE GET DISCONNECTED WHILE DOING THIS, THINGS WILL GO WRONG
- // NEED TO UPDATE THIS LOGIC
- CFDataReplaceBytes((CFMutableDataRef)sendFirstItem, CFRangeMake(0, written), NULL, 0);
- return;
- }
-
- // we are done sending the first item in the queue, remove it now
- pthread_mutex_lock(&logger->logQueueMutex);
- CFArrayRemoveValueAtIndex(logger->logQueue, 0);
- logger->incompleteSendOfFirstItem = NO;
- pthread_mutex_unlock(&logger->logQueueMutex);
- logger->sendBufferOffset = 0;
- }
- }
-}
-
-// -----------------------------------------------------------------------------
-#pragma mark -
-#pragma mark File buffering functions
-// -----------------------------------------------------------------------------
-static void LoggerCreateBufferWriteStream(Logger *logger)
-{
- LOGGERDBG(CFSTR("LoggerCreateBufferWriteStream to file %@"), logger->bufferFile);
- CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, logger->bufferFile, kCFURLPOSIXPathStyle, false);
- if (fileURL != NULL)
- {
- // Create write stream to file
- logger->bufferWriteStream = CFWriteStreamCreateWithFile(NULL, fileURL);
- CFRelease(fileURL);
- if (logger->bufferWriteStream != NULL)
- {
- // Set flag to append new data to buffer file
- CFWriteStreamSetProperty(logger->bufferWriteStream, kCFStreamPropertyAppendToFile, kCFBooleanTrue);
-
- // Open the buffer stream for writing
- if (!CFWriteStreamOpen(logger->bufferWriteStream))
- {
- CFRelease(logger->bufferWriteStream);
- logger->bufferWriteStream = NULL;
- }
- else
- {
- // Write client info and flush the queue contents to buffer file
- LoggerPushClientInfoToFrontOfQueue(logger);
- LoggerFlushQueueToBufferStream(logger, YES);
- }
- }
- }
- if (logger->bufferWriteStream == NULL)
- {
- CFShow(CFSTR("NSLogger Warning: failed opening buffer file for writing:"));
- CFShow(logger->bufferFile);
- }
-}
-
-static void LoggerCreateBufferReadStream(Logger *logger)
-{
- LOGGERDBG(CFSTR("LoggerCreateBufferReadStream from file %@"), logger->bufferFile);
- CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, logger->bufferFile, kCFURLPOSIXPathStyle, false);
- if (fileURL != NULL)
- {
- // Create read stream from file
- logger->bufferReadStream = CFReadStreamCreateWithFile(NULL, fileURL);
- CFRelease(fileURL);
- if (logger->bufferReadStream != NULL)
- {
- if (!CFReadStreamOpen(logger->bufferReadStream))
- {
- CFRelease(logger->bufferReadStream);
- logger->bufferReadStream = NULL;
- }
- }
- }
-}
-
-static void LoggerEmptyBufferFile(Logger *logger)
-{
- // completely remove the buffer file from storage
- LOGGERDBG(CFSTR("LoggerEmptyBufferFile %@"), logger->bufferFile);
- if (logger->bufferFile != NULL)
- {
- CFIndex bufferSize = 1 + CFStringGetLength(logger->bufferFile) * 3;
- char *buffer = (char *)malloc(bufferSize);
- if (buffer != NULL)
- {
- if (CFStringGetFileSystemRepresentation(logger->bufferFile, buffer, bufferSize))
- {
- // remove file
- unlink(buffer);
- }
- free(buffer);
- }
- }
-}
-
-static void LoggerFileBufferingOptionsChanged(Logger *logger)
-{
- // File buffering options changed:
- // - close the current buffer file stream, if any
- // - create a new one, if needed
- LOGGERDBG(CFSTR("LoggerFileBufferingOptionsChanged bufferFile=%@"), logger->bufferFile);
- if (logger->bufferWriteStream != NULL)
- {
- CFWriteStreamClose(logger->bufferWriteStream);
- CFRelease(logger->bufferWriteStream);
- logger->bufferWriteStream = NULL;
- }
- if (logger->bufferFile != NULL)
- LoggerCreateBufferWriteStream(logger);
-}
-
-static void LoggerFlushQueueToBufferStream(Logger *logger, BOOL firstEntryIsClientInfo)
-{
- LOGGERDBG(CFSTR("LoggerFlushQueueToBufferStream"));
- pthread_mutex_lock(&logger->logQueueMutex);
- if (logger->incompleteSendOfFirstItem)
- {
- // drop anything being sent
- logger->sendBufferUsed = 0;
- logger->sendBufferOffset = 0;
- }
- logger->incompleteSendOfFirstItem = NO;
-
- // Write outstanding messages to the buffer file (streams don't detect disconnection
- // until the next write, where we could lose one or more messages)
- if (!firstEntryIsClientInfo && logger->sendBufferUsed)
- CFWriteStreamWrite(logger->bufferWriteStream, logger->sendBuffer + logger->sendBufferOffset, logger->sendBufferUsed - logger->sendBufferOffset);
-
- int n = 0;
- while (CFArrayGetCount(logger->logQueue))
- {
- CFDataRef data = CFArrayGetValueAtIndex(logger->logQueue, 0);
- CFIndex dataLength = CFDataGetLength(data);
- CFIndex written = CFWriteStreamWrite(logger->bufferWriteStream, CFDataGetBytePtr(data), dataLength);
- if (written != dataLength)
- {
- // couldn't write all data to file, maybe storage run out of space?
- CFShow(CFSTR("NSLogger Error: failed flushing the whole queue to buffer file:"));
- CFShow(logger->bufferFile);
- break;
- }
- CFArrayRemoveValueAtIndex(logger->logQueue, 0);
- if (n == 0 && firstEntryIsClientInfo && logger->sendBufferUsed)
- {
- // try hard: write any outstanding messages to the buffer file, after the client info
- CFWriteStreamWrite(logger->bufferWriteStream, logger->sendBuffer + logger->sendBufferOffset, logger->sendBufferUsed - logger->sendBufferOffset);
- }
- n++;
- }
- logger->sendBufferUsed = 0;
- logger->sendBufferOffset = 0;
- pthread_mutex_unlock(&logger->logQueueMutex);
-}
-
-// -----------------------------------------------------------------------------
-#pragma mark -
-#pragma mark Bonjour browsing
-// -----------------------------------------------------------------------------
-static void LoggerStartBonjourBrowsing(Logger *logger)
-{
- LOGGERDBG(CFSTR("LoggerStartBonjourBrowsing"));
-
- if (logger->options & kLoggerOption_BrowseOnlyLocalDomain)
- {
- LOGGERDBG(CFSTR("Logger configured to search only the local domain, searching for services on: local."));
- if (!LoggerBrowseBonjourForServices(logger, CFSTR("local.")) && logger->host == NULL)
- {
- LOGGERDBG(CFSTR("*** Logger: could not browse for services in domain local., no remote host configured: reverting to console logging. ***"));
- logger->options |= kLoggerOption_LogToConsole;
- }
- }
- else
- {
- LOGGERDBG(CFSTR("Logger configured to search all domains, browsing for domains first"));
- CFNetServiceClientContext context = {0, (void *)logger, NULL, NULL, NULL};
- CFRunLoopRef runLoop = CFRunLoopGetCurrent();
- logger->bonjourDomainBrowser = CFNetServiceBrowserCreate(NULL, &LoggerServiceBrowserCallBack, &context);
- CFNetServiceBrowserScheduleWithRunLoop(logger->bonjourDomainBrowser, runLoop, kCFRunLoopCommonModes);
- if (!CFNetServiceBrowserSearchForDomains(logger->bonjourDomainBrowser, false, NULL))
- {
- // An error occurred, revert to console logging if there is no remote host
- LOGGERDBG(CFSTR("*** Logger: could not browse for domains, reverting to console logging. ***"));
- CFNetServiceBrowserUnscheduleFromRunLoop(logger->bonjourDomainBrowser, runLoop, kCFRunLoopCommonModes);
- CFRelease(logger->bonjourDomainBrowser);
- logger->bonjourDomainBrowser = NULL;
- if (logger->host == NULL)
- logger->options |= kLoggerOption_LogToConsole;
- }
- }
-}
-
-static void LoggerStopBonjourBrowsing(Logger *logger)
-{
- LOGGERDBG(CFSTR("LoggerStopBonjourBrowsing"));
-
- // stop browsing for domains
- if (logger->bonjourDomainBrowser != NULL)
- {
- CFNetServiceBrowserStopSearch(logger->bonjourDomainBrowser, NULL);
- CFNetServiceBrowserUnscheduleFromRunLoop(logger->bonjourDomainBrowser, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- CFNetServiceBrowserInvalidate(logger->bonjourDomainBrowser);
- CFRelease(logger->bonjourDomainBrowser);
- logger->bonjourDomainBrowser = NULL;
- }
-
- // stop browsing for services
- CFIndex idx;
- for (idx = 0; idx < CFArrayGetCount(logger->bonjourServiceBrowsers); idx++)
- {
- CFNetServiceBrowserRef browser = (CFNetServiceBrowserRef)CFArrayGetValueAtIndex(logger->bonjourServiceBrowsers, idx);
- CFNetServiceBrowserStopSearch(browser, NULL);
- CFNetServiceBrowserUnscheduleFromRunLoop(browser, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- CFNetServiceBrowserInvalidate(browser);
- }
- CFArrayRemoveAllValues(logger->bonjourServiceBrowsers);
-
- // Forget all services
- CFArrayRemoveAllValues(logger->bonjourServices);
-}
-
-static BOOL LoggerBrowseBonjourForServices(Logger *logger, CFStringRef domainName)
-{
- BOOL result = NO;
- CFNetServiceClientContext context = {0, (void *)logger, NULL, NULL, NULL};
- CFRunLoopRef runLoop = CFRunLoopGetCurrent();
-
- CFNetServiceBrowserRef browser = CFNetServiceBrowserCreate(NULL, (CFNetServiceBrowserClientCallBack)&LoggerServiceBrowserCallBack, &context);
- CFNetServiceBrowserScheduleWithRunLoop(browser, runLoop, kCFRunLoopCommonModes);
- CFStreamError error;
-
- // try to use the user-specfied service type if any, fallback on our
- // default service type
- CFStringRef serviceType = logger->bonjourServiceType;
- if (serviceType == NULL)
- {
- if (logger->options & kLoggerOption_UseSSL)
- serviceType = LOGGER_SERVICE_TYPE_SSL;
- else
- serviceType = LOGGER_SERVICE_TYPE;
- }
- if (!CFNetServiceBrowserSearchForServices(browser, domainName, serviceType, &error))
- {
- LOGGERDBG(CFSTR("Logger can't start search on domain: %@ (error %d)"), domainName, error.error);
- CFNetServiceBrowserUnscheduleFromRunLoop(browser, runLoop, kCFRunLoopCommonModes);
- CFNetServiceBrowserInvalidate(browser);
- }
- else
- {
- LOGGERDBG(CFSTR("Logger started search for services of type %@ in domain %@"), serviceType, domainName);
- CFArrayAppendValue(logger->bonjourServiceBrowsers, browser);
- result = YES;
- }
- CFRelease(browser);
- return result;
-}
-
-static void LoggerServiceBrowserCallBack (CFNetServiceBrowserRef browser,
- CFOptionFlags flags,
- CFTypeRef domainOrService,
- CFStreamError* error,
- void* info)
-{
- LOGGERDBG(CFSTR("LoggerServiceBrowserCallback browser=%@ flags=0x%04x domainOrService=%@ error=%d"), browser, flags, domainOrService, error==NULL ? 0 : error->error);
-
- Logger *logger = (Logger *)info;
- assert(logger != NULL);
-
- if (flags & kCFNetServiceFlagRemove)
- {
- if (!(flags & kCFNetServiceFlagIsDomain))
- {
- CFNetServiceRef service = (CFNetServiceRef)domainOrService;
- CFIndex idx;
- for (idx = 0; idx < CFArrayGetCount(logger->bonjourServices); idx++)
- {
- if (CFArrayGetValueAtIndex(logger->bonjourServices, idx) == service)
- {
- CFNetServiceUnscheduleFromRunLoop(service, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- CFNetServiceClientContext context = {0, NULL, NULL, NULL, NULL};
- CFNetServiceSetClient(service, NULL, &context);
- CFNetServiceCancel(service);
- CFArrayRemoveValueAtIndex(logger->bonjourServices, idx);
- break;
- }
- }
- }
- }
- else
- {
- if (flags & kCFNetServiceFlagIsDomain)
- {
- // start searching for services in this domain
- LoggerBrowseBonjourForServices(logger, (CFStringRef)domainOrService);
- }
- else
- {
- // a service has been found
- LOGGERDBG(CFSTR("Logger found service: %@"), domainOrService);
- CFNetServiceRef service = (CFNetServiceRef)domainOrService;
- if (service != NULL)
- {
- // if the user has specified that Logger shall only connect to the specified
- // Bonjour service name, check it now. This makes things easier in a teamwork
- // environment where multiple instances of NSLogger viewer may run on the
- // same network
- if (logger->bonjourServiceName != NULL)
- {
- LOGGERDBG(CFSTR("-> looking for services of name %@"), logger->bonjourServiceName);
- CFStringRef name = CFNetServiceGetName(service);
- if (name == NULL || kCFCompareEqualTo != CFStringCompare(name, logger->bonjourServiceName, kCFCompareCaseInsensitive | kCFCompareDiacriticInsensitive))
- {
- LOGGERDBG(CFSTR("-> service name %@ does not match requested service name, ignoring."), name, logger->bonjourServiceName);
- return;
- }
- }
- CFArrayAppendValue(logger->bonjourServices, service);
- LoggerTryConnect(logger);
- }
- }
- }
-}
-
-// -----------------------------------------------------------------------------
-#pragma mark -
-#pragma mark Reachability
-// -----------------------------------------------------------------------------
-static void LoggerStartReachabilityChecking(Logger *logger)
-{
- if (logger->host != NULL && logger->reachability == NULL)
- {
- LOGGERDBG(CFSTR("Starting SCNetworkReachability to wait for host %@ to be reachable"), logger->host);
-
- CFIndex length = CFStringGetLength(logger->host) * 3;
- char *buffer = (char *)malloc(length + 1);
- CFStringGetBytes(logger->host, CFRangeMake(0, CFStringGetLength(logger->host)), kCFStringEncodingUTF8, '?', false, (UInt8 *)buffer, length, &length);
- buffer[length] = 0;
-
- logger->reachability = SCNetworkReachabilityCreateWithName(NULL, buffer);
-
- SCNetworkReachabilityContext context = {0, logger, NULL, NULL, NULL};
- SCNetworkReachabilitySetCallback(logger->reachability, &LoggerReachabilityCallBack, &context);
- SCNetworkReachabilityScheduleWithRunLoop(logger->reachability, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
-
- free(buffer);
-
- // Also start a timer that will try to reconnect every N seconds
- if (logger->checkHostTimer == NULL)
- {
- CFRunLoopTimerContext timerContext = {
- .version = 0,
- .info = logger,
- .retain = NULL,
- .release = NULL,
- .copyDescription = NULL
- };
- logger->checkHostTimer = CFRunLoopTimerCreate(NULL,
- CFAbsoluteTimeGetCurrent() + 5,
- 5, // reconnect interval
- 0,
- 0,
- &LoggerTimedReconnectCallback,
- &timerContext);
- if (logger->checkHostTimer != NULL)
- {
- LOGGERDBG(CFSTR("Starting the TimedReconnect timer to regularly retry the connection"));
- CFRunLoopAddTimer(CFRunLoopGetCurrent(), logger->checkHostTimer, kCFRunLoopCommonModes);
- }
- }
- }
-}
-
-static void LoggerStopReachabilityChecking(Logger *logger)
-{
- if (logger->reachability != NULL)
- {
- LOGGERDBG(CFSTR("Stopping SCNetworkReachability"));
- SCNetworkReachabilityUnscheduleFromRunLoop(logger->reachability, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- CFRelease(logger->reachability);
- logger->reachability = NULL;
- }
- if (logger->checkHostTimer != NULL)
- {
- CFRunLoopTimerInvalidate(logger->checkHostTimer);
- CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), logger->checkHostTimer, kCFRunLoopCommonModes);
- CFRelease(logger->checkHostTimer);
- logger->checkHostTimer = NULL;
- }
-}
-
-static void LoggerReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
-{
- Logger *logger = (Logger *)info;
- assert(logger != NULL);
- LOGGERDBG(CFSTR("LoggerReachabilityCallBack called with flags=0x%08lx"), flags);
- if (flags & kSCNetworkReachabilityFlagsReachable)
- {
- // target host became reachable. If we have not other open connection,
- // try direct connection to the host
- if (logger->logStream == NULL && logger->host != NULL)
- {
- LOGGERDBG(CFSTR("-> host %@ became reachable, trying to connect."), logger->host);
- LoggerTryConnect(logger);
- }
- }
-}
-
-static void LoggerTimedReconnectCallback(CFRunLoopTimerRef timer, void *info)
-{
- Logger *logger = (Logger *)info;
- assert(logger != NULL);
- LOGGERDBG(CFSTR("LoggerTimedReconnectCallback"));
- if (logger->logStream == NULL && logger->host != NULL)
- {
- LOGGERDBG(CFSTR("-> trying to reconnect to host %@"), logger->host);
- LoggerTryConnect(logger);
- }
- else
- {
- LOGGERDBG(CFSTR("-> timer not needed anymore, removing it form runloop"));
- CFRunLoopTimerInvalidate(timer);
- CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), logger->checkHostTimer, kCFRunLoopCommonModes);
- CFRelease(timer);
- logger->checkHostTimer = NULL;
- }
-}
-
-// -----------------------------------------------------------------------------
-#pragma mark -
-#pragma mark Stream management
-// -----------------------------------------------------------------------------
-static BOOL LoggerConfigureAndOpenStream(Logger *logger)
-{
- // configure and open stream
- LOGGERDBG(CFSTR("LoggerConfigureAndOpenStream configuring and opening log stream"));
- CFStreamClientContext context = {0, (void *)logger, NULL, NULL, NULL};
- if (CFWriteStreamSetClient(logger->logStream,
- (kCFStreamEventOpenCompleted |
- kCFStreamEventCanAcceptBytes |
- kCFStreamEventErrorOccurred |
- kCFStreamEventEndEncountered),
- &LoggerWriteStreamCallback,
- &context))
- {
- if (logger->options & kLoggerOption_UseSSL)
- {
- // Configure stream to require a SSL connection
- LOGGERDBG(CFSTR("-> configuring SSL"));
- const void *SSLKeys[] = {
- kCFStreamSSLLevel,
- kCFStreamSSLValidatesCertificateChain,
- kCFStreamSSLIsServer,
- kCFStreamSSLPeerName
- };
- const void *SSLValues[] = {
- kCFStreamSocketSecurityLevelNegotiatedSSL,
- kCFBooleanFalse, // no certificate chain validation (we use a self-signed certificate)
- kCFBooleanFalse, // not a server
- kCFNull
- };
- CFDictionaryRef SSLDict = CFDictionaryCreate(NULL, SSLKeys, SSLValues, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFWriteStreamSetProperty(logger->logStream, kCFStreamPropertySSLSettings, SSLDict);
- CFRelease(SSLDict);
- }
-
- CFWriteStreamScheduleWithRunLoop(logger->logStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
-
- if (CFWriteStreamOpen(logger->logStream))
- {
- LOGGERDBG(CFSTR("-> stream open attempt, waiting for open completion"));
- return YES;
- }
-
- LOGGERDBG(CFSTR("-> stream open failed."));
-
- CFWriteStreamSetClient(logger->logStream, kCFStreamEventNone, NULL, NULL);
- if (CFWriteStreamGetStatus(logger->logStream) == kCFStreamStatusOpen)