├── README.md
├── cpapm.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ └── yangyouyong.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ └── yangyouyong.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── WellTangAPM.xcscheme
│ ├── cpapm.xcscheme
│ └── xcschememanagement.plist
└── cpapm
├── APM
├── ANT
│ ├── ANT.h
│ ├── ANT.m
│ ├── ANTPingThread.h
│ └── ANTPingThread.m
├── CrashANT
│ ├── CrashCatcher.h
│ ├── CrashCatcher.m
│ ├── NSObject+MethodSwizzleList.h
│ ├── NSObject+MethodSwizzleList.m
│ ├── OriginalObjectMethod+Swizzle.h
│ ├── OriginalObjectMethod+Swizzle.m
│ ├── OriginalObjectMethod.h
│ ├── OriginalObjectMethod.m
│ ├── fishhook.c
│ ├── fishhook.h
│ ├── method_check.c
│ └── method_check.h
├── Dependency
│ └── Backtrace
│ │ ├── BSBacktraceLogger.h
│ │ ├── BSBacktraceLogger.m
│ │ ├── WTBacktrace.h
│ │ └── WTBacktrace.m
├── Leaks
│ ├── DetectorProtocol.h
│ ├── NSObject+Detector.h
│ ├── NSObject+Detector.m
│ ├── UINavigationController+Detector.h
│ ├── UINavigationController+Detector.m
│ ├── UIView+Detector.h
│ ├── UIView+Detector.m
│ ├── UIViewController+Detector.h
│ ├── UIViewController+Detector.m
│ ├── WTLeaksDetector.h
│ ├── WTLeaksDetector.m
│ ├── WTObjectProxy.h
│ └── WTObjectProxy.m
└── Net
│ ├── CFNet.h
│ ├── CFNet.m
│ ├── CFNetProxy.h
│ ├── CFNetProxy.m
│ ├── CFNetProxyModel.h
│ ├── CFNetProxyModel.m
│ ├── Hook_CFNetwork.h
│ ├── Hook_CFNetwork.m
│ ├── NetAnt.h
│ ├── NetAnt.m
│ ├── NetAntURLSessionConfiguration.h
│ ├── NetAntURLSessionConfiguration.m
│ ├── NetProtocol.h
│ ├── NetProtocol.m
│ └── SocketBasedRequest
│ ├── CHttpRequest.c
│ ├── CHttpRequest.h
│ ├── HTTPRequest.hpp
│ ├── XXNetwork.h
│ └── XXNetwork.mm
└── APP
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
└── AppIcon.appiconset
│ └── Contents.json
├── Base.lproj
├── LaunchScreen.storyboard
└── Main.storyboard
├── Crash
├── CrashViewController.h
├── CrashViewController.m
├── EVGView.h
└── EVGView.m
├── Info.plist
├── Leaks
├── LeaksViewController.h
└── LeaksViewController.m
├── Net
├── NetViewController.h
└── NetViewController.m
├── Trace
├── TraceViewController.h
└── TraceViewController.m
├── ViewController.h
├── ViewController.m
└── main.mm
/README.md:
--------------------------------------------------------------------------------
1 | ## iOS监控
2 |
3 | 1. [卡顿监控](#Blocked)
4 | 1. [内存泄露监控](#Leaks)
5 | 1. [网络监控](#Network)
6 | * [基于CFNetwork的监控](#fishhook)
7 | 1. [crash监控](#Crash)
8 | 1. [方法调换监控](#HookCheck)
9 |
10 | ### 卡顿监控
11 |
12 | > 通过分析栈调用情况自顶向下查找卡顿的方法调用
13 |
14 | ```
15 | 2018-01-11 14:29:12.493901+0800 cpapm[16525:25693273] ----mainTrace----
16 | 2018-01-11 14:29:12.494088+0800 cpapm[16525:25693273] Backtrace of Thread 771:
17 | libsystem_platform.dylib 0x114e71f49 _platform_memmove$VARIANT$Haswell + 41
18 | CoreFoundation 0x110f2b3d0 _CFStringCheckAndGetCharacters + 240
19 | CoreFoundation 0x110f2b282 -[__NSCFString getCharacters:range:] + 34
20 | Foundation 0x11007fd38 _NSNewStringByAppendingStrings + 1071
21 | Foundation 0x1100a2b2f -[NSString stringByAppendingString:] + 185
22 | cpapm 0x10fd734b0 -[TraceViewController blockFoo] + 128
23 | cpapm 0x10fd733f1 -[TraceViewController ANTTask:] + 257
24 | UIKit 0x111488972 -[UIApplication sendAction:to:from:forEvent:] + 83
25 | UIKit 0x111607c3c -[UIControl sendAction:to:forEvent:] + 67
26 | UIKit 0x111607f59 -[UIControl _sendActionsForEvents:withEvent:] + 450
27 | UIKit 0x111606e86 -[UIControl touchesEnded:withEvent:] + 618
28 | UIKit 0x1114fe807 -[UIWindow _sendTouchesForEvent:] + 2807
29 |
30 | ```
31 |
32 | ### 内存泄露监控
33 |
34 | > 查看内存泄露的日志, 定位到具体的类. 可加入FBRetainCycle 找到具体引用关系
35 |
36 | ```
37 | 2018-01-11 14:32:33.153020+0800 cpapm[16525:25692073] *** is still alive ***
38 | 2018-01-11 14:32:33.153255+0800 cpapm[16525:25692073]
39 |
40 | Detect Possible Controller Leak: LeaksViewController
41 |
42 | ```
43 |
44 | ### 网络监控
45 |
46 | > 通过设置代理 拿到每次网络请求的入参及返回值 做一些事情(如网络本地缓存, 网络调试等, 网络性能监控等)
47 |
48 | ```
49 | // catch any network based on NSURLProtocol
50 | -(void)netAntDidCatchRequest:(NSURLRequest *)request response:(NSURLResponse *)response data:(NSData *)data {
51 | id obj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
52 | if (obj == nil) {
53 | obj = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
54 | }
55 | NSLog(@"catch_request:%@\nresponse:%@,\ndata:%@",request.URL.absoluteString, response.URL.absoluteString, obj);
56 | }
57 |
58 | ```
59 |
60 | #### 基于CFNetwork的监控
61 |
62 | > 拦截CFNetwork 下的网络请求. 校验DNS拦截, 请求信息, 网络性能, 响应时间等信息.
63 | >
64 | > 暂时未做响应body的拦截
65 |
66 | ```
67 | void hooked_proxyCallBack(CFReadStreamRef stream,CFStreamEventType type,void *clientCallBackInfo){
68 |
69 | NSDictionary *proxyInfo = CFBridgingRelease(CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPProxy));
70 | NSString *requestId = proxyInfo[CFRequest_KEY];
71 | NSMutableDictionary *proxyCallBackMap = [CFNetProxy sharedInstance].requestMap;
72 |
73 | CFReadStreamClientCallBack original_callback = NULL;
74 | if (clientCallBackInfo != NULL) {
75 | CFNetProxyModel *proxy = proxyCallBackMap[requestId];
76 | if (proxy) {
77 | original_callback = [proxy.callbackPointer pointerValue];
78 | }else{
79 | NSLog(@"missed_data");
80 | }
81 | }
82 |
83 | CFReadStreamRef readStream = stream;
84 |
85 | if(type == kCFStreamEventHasBytesAvailable){
86 |
87 | CFNetProxyModel *proxy = proxyCallBackMap[requestId];
88 | if (proxy) {
89 | // proxy receive data
90 | /**
91 | UInt8 buff[255];
92 | long length = CFReadStreamRead(stream, buff, 255);
93 | NSMutableData *mutiData = proxy.bufferData;
94 | if(!mutiData){
95 | mutiData = [[NSMutableData alloc] init];
96 | }
97 | [mutiData appendBytes:buff length:length];
98 |
99 | proxy.bufferData = mutiData;
100 | */
101 | }
102 |
103 | }else if(type == kCFStreamEventEndEncountered){
104 |
105 | // end data
106 | CFNetProxyModel *proxy = proxyCallBackMap[requestId];
107 | if (proxy) {
108 | proxy.responseData = proxy.bufferData;
109 | }
110 | NSLog(@"proxy complete");
111 | }
112 |
113 | if (original_callback != NULL) {
114 | original_callback(readStream, type, clientCallBackInfo);
115 | }
116 | }
117 |
118 | ```
119 |
120 |
121 | ### crash监控
122 |
123 | > 通过拦截NSExecption对象 和拦截single 对象捕获crash 做crash 上报等事情.
124 |
125 | ```
126 | / you can report logs here or store them
127 | -(void)logLocalException:(NSException *)exception {
128 |
129 | NSArray *stackArray = [CrashCatcher backtrace];
130 | NSString *reason = [exception reason];
131 | NSString *name = [exception name];
132 | NSString *exceptionInfo = [NSString stringWithFormat:@"Exception reason:%@\nException name:%@\nException stack:%@\nUserInfo:%@\n",name, reason, stackArray,exception.userInfo];
133 |
134 | NSString *logFilePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject stringByAppendingPathComponent:@"debug_exception_log.txt"];
135 | NSFileManager *manager = [NSFileManager defaultManager];
136 | if(![manager fileExistsAtPath:logFilePath]){
137 | [manager createFileAtPath:logFilePath contents:[exceptionInfo dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
138 | }else{
139 | NSData *data = [NSData dataWithContentsOfFile:logFilePath];
140 | NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
141 | contents = [contents stringByAppendingString:exceptionInfo];
142 | [contents writeToFile:logFilePath atomically:true encoding:NSUTF8StringEncoding error:nil];
143 | }
144 | }
145 |
146 | ```
147 |
148 | ### 方法调换监控
149 |
150 | > 通过C方法查找到当前类哪些方法被hook掉或者被category重写了. 用于hook系统方法前的检测
151 |
152 | ```
153 |
154 | 2018-01-11 14:40:35.325799+0800 cpapm[16525:25692073] swizzledInfo:(
155 | {
156 | originalName = Small;
157 | swizzledMethodName = "-[OriginalObjectMethod(Swizzle) swizzle_Small]";
158 | },
159 | {
160 | originalName = Foo;
161 | swizzledMethodName = "-[OriginalObjectMethod(Swizzle) swizzle_Foo]";
162 | },
163 | {
164 | originalName = write;
165 | swizzledMethodName = "-[OriginalObjectMethod(Swizzle) write]";
166 | },
167 | {
168 | originalName = "swizzle_Small";
169 | swizzledMethodName = "-[OriginalObjectMethod Small]";
170 | },
171 | {
172 | originalName = "swizzle_Foo";
173 | swizzledMethodName = "-[OriginalObjectMethod Foo]";
174 | }
175 | )
176 |
177 | ```
178 |
179 |
180 |
181 | TODO:
182 | > fishhook 监控基于CFNetwork的网络请求
183 |
184 | > CPU爆表 & 内存爆表监控
185 |
186 | > PLeakSniffer 再造
187 |
188 | > FileManager
189 |
190 | > ...
--------------------------------------------------------------------------------
/cpapm.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/cpapm.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/cpapm.xcodeproj/project.xcworkspace/xcuserdata/yangyouyong.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YangYouYong/cpapm/16001e684aa386ec77c36038acbcffb832fba18d/cpapm.xcodeproj/project.xcworkspace/xcuserdata/yangyouyong.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/cpapm.xcodeproj/xcuserdata/yangyouyong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
22 |
23 |
24 |
26 |
39 |
40 |
41 |
43 |
56 |
57 |
58 |
60 |
73 |
74 |
75 |
77 |
90 |
91 |
92 |
94 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/cpapm.xcodeproj/xcuserdata/yangyouyong.xcuserdatad/xcschemes/WellTangAPM.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
44 |
50 |
51 |
52 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
76 |
78 |
84 |
85 |
86 |
87 |
88 |
89 |
95 |
97 |
103 |
104 |
105 |
106 |
108 |
109 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/cpapm.xcodeproj/xcuserdata/yangyouyong.xcuserdatad/xcschemes/cpapm.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
44 |
50 |
51 |
52 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
76 |
78 |
84 |
85 |
86 |
87 |
88 |
89 |
95 |
97 |
103 |
104 |
105 |
106 |
108 |
109 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/cpapm.xcodeproj/xcuserdata/yangyouyong.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | WellTangAPM.xcscheme
8 |
9 | orderHint
10 | 1
11 |
12 | cpapm.xcscheme
13 |
14 | orderHint
15 | 0
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | C06A5DA01FF4881E0013FB75
21 |
22 | primary
23 |
24 |
25 | C06A5DB81FF4881F0013FB75
26 |
27 | primary
28 |
29 |
30 | C06A5DC31FF4881F0013FB75
31 |
32 | primary
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/cpapm/APM/ANT/ANT.h:
--------------------------------------------------------------------------------
1 | //
2 | // ANT.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class ANT;
12 | @protocol ANTDelegate
13 |
14 | -(void)ANT:(ANT *)ant
15 | catchWithThreadHold:(double)threadHold
16 | mainThreadBacktrace:(NSString *)mainBacktrace
17 | allThreadBacktrace:(NSString *)allBacktrace;
18 |
19 | @end
20 |
21 | @interface ANT : NSObject
22 |
23 | @property (nonatomic, assign) id delegate;
24 | @property (nonatomic, assign, readonly) BOOL isOpen;
25 |
26 | -(void)openWithThreadhold:(double)threadHold;
27 | -(void)close;
28 |
29 | @end
30 |
31 |
--------------------------------------------------------------------------------
/cpapm/APM/ANT/ANT.m:
--------------------------------------------------------------------------------
1 | //
2 | // ANT.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "ANT.h"
10 | #import "WTBacktrace.h"
11 | #import "ANTPingThread.h"
12 |
13 | @interface ANT()
14 |
15 | @property (nonatomic, strong) ANTPingThread *pingThread;
16 |
17 | @end
18 |
19 | @implementation ANT
20 |
21 | -(BOOL)isOpen {
22 | return !self.pingThread.isCancelled;
23 | }
24 |
25 | -(void)openWithThreadhold:(double)threadHold {
26 |
27 | self.pingThread = [ANTPingThread new];
28 | __weak typeof(self) weakSelf = self;
29 | [self.pingThread startWithThreadHold:threadHold completion:^{
30 | NSString *main = [WTBacktrace mainThread];
31 | NSString *all = [WTBacktrace allThread];
32 | if (!weakSelf) {
33 | return ;
34 | }
35 | [weakSelf.delegate ANT:weakSelf
36 | catchWithThreadHold:threadHold
37 | mainThreadBacktrace:main
38 | allThreadBacktrace:all];
39 | }];
40 | }
41 |
42 | -(void)close {
43 | [self.pingThread cancel];
44 | }
45 |
46 | -(void)dealloc {
47 | [self.pingThread cancel];
48 | }
49 |
50 | @end
51 |
52 |
--------------------------------------------------------------------------------
/cpapm/APM/ANT/ANTPingThread.h:
--------------------------------------------------------------------------------
1 | //
2 | // ANTPingThread.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef void(^ANTPingThreadCallBack)(void);
12 |
13 | @interface ANTPingThread : NSThread
14 |
15 | -(void)startWithThreadHold:(double)threadHold
16 | completion:(ANTPingThreadCallBack)completionBlock;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/cpapm/APM/ANT/ANTPingThread.m:
--------------------------------------------------------------------------------
1 | //
2 | // ANTPingThread.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "ANTPingThread.h"
10 |
11 | @interface ANTPingThread()
12 |
13 | @property (nonatomic, copy) ANTPingThreadCallBack completion;
14 | @property (nonatomic, assign) double threadHold;
15 | @property (nonatomic, strong) dispatch_semaphore_t semaphore;
16 | @property (nonatomic, assign) BOOL isMainThreadBlock;
17 |
18 | @end
19 |
20 | @implementation ANTPingThread
21 |
22 | -(instancetype)init {
23 | if (self = [super init]) {
24 | self.semaphore = dispatch_semaphore_create(0);
25 | self.threadHold = 0.4;
26 | }
27 | return self;
28 | }
29 |
30 | -(void)startWithThreadHold:(double)threadHold completion:(ANTPingThreadCallBack)completionBlock {
31 | self.threadHold = threadHold;
32 | self.completion = completionBlock;
33 | [self start];
34 | }
35 |
36 | -(void)main {
37 |
38 | while (self.isCancelled == false) {
39 | self.isMainThreadBlock = true;
40 | dispatch_async(dispatch_get_main_queue(), ^{
41 | self.isMainThreadBlock = false;
42 | dispatch_semaphore_signal(self.semaphore);
43 | });
44 |
45 | [NSThread sleepForTimeInterval:self.threadHold];
46 | if (self.isMainThreadBlock) {
47 | if (self.completion) {
48 | self.completion();
49 | }
50 | }
51 |
52 | dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
53 | }
54 | }
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/CrashCatcher.h:
--------------------------------------------------------------------------------
1 | //
2 | // CrashCatcher.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/3.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CrashCatcher : NSObject
12 |
13 | +(instancetype)sharedInstance;
14 |
15 | +(NSArray *)backtrace; // return call stacks
16 |
17 | -(void)setOpen:(BOOL)open;
18 |
19 | -(NSString *)nameOfSignal:(int)signalType;
20 |
21 | -(void)killApp;
22 |
23 | void catchCrash(NSException *exception);
24 |
25 | /////////////////// signal type and funcs //////////////////
26 |
27 | void receiveSignal(int signalType);
28 |
29 | ////////////////////////////////////////////////////////////
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/CrashCatcher.m:
--------------------------------------------------------------------------------
1 | //
2 | // CrashCatcher.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/3.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #include
10 | #import "CrashCatcher.h"
11 | #include
12 | #include
13 |
14 | //signal信号名
15 | NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";
16 | NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey";
17 | NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";
18 |
19 | volatile int32_t UncaughtExceptionCount = 0;
20 | const int32_t UncaughtExceptionMaximum = 10; //表示最多只截获10次异常,如果超过十次则不截获弹出alter了直接崩溃
21 |
22 | const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4;
23 | const NSInteger UncaughtExceptionHandlerReportAddressCount = 13;
24 |
25 | @interface CrashCatcher()
26 |
27 | @property (nonatomic, assign) NSTimeInterval execptionTime;
28 |
29 | @end
30 |
31 | @implementation CrashCatcher
32 |
33 | +(instancetype)sharedInstance {
34 | static CrashCatcher *sharedInstance = nil;
35 | static dispatch_once_t onceToken;
36 | dispatch_once(&onceToken, ^{
37 | sharedInstance = [[CrashCatcher alloc] init];
38 | sharedInstance.execptionTime = 30;
39 | });
40 |
41 | return sharedInstance;
42 | }
43 |
44 | + (NSArray *)backtrace
45 | {
46 | void* callstack[128];
47 | int frames = backtrace(callstack, 128);
48 | char **strs = backtrace_symbols(callstack, frames);
49 |
50 | int i;
51 | NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
52 | for (
53 | i = UncaughtExceptionHandlerSkipAddressCount;
54 | i < UncaughtExceptionHandlerSkipAddressCount +
55 | UncaughtExceptionHandlerReportAddressCount;
56 | i++)
57 | {
58 | [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
59 | }
60 | free(strs);
61 |
62 | return backtrace;
63 | }
64 |
65 | -(void)setOpen:(BOOL)open {
66 | if (open) {
67 | NSSetUncaughtExceptionHandler(&catchCrash);
68 | setCrashSignalHandler();
69 | }
70 | }
71 |
72 | - (void)handleException:(NSException *)exception{
73 |
74 | CFRunLoopRef runLoop = CFRunLoopGetCurrent();
75 | CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
76 |
77 |
78 | while (self.execptionTime > 0)
79 | {
80 | for (NSString *mode in (__bridge NSArray *)allModes)
81 | {
82 | //为阻止线程退出,使用 CFRunLoopRunInMode(model, 0.001, false)等待系统消息,false表示RunLoop没有超时时间
83 | CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
84 | self.execptionTime -= 0.001;
85 | }
86 | }
87 |
88 | CFRelease(allModes);
89 |
90 | NSSetUncaughtExceptionHandler(NULL);
91 | signal(SIGABRT, SIG_DFL);
92 | signal(SIGILL, SIG_DFL);
93 | signal(SIGSEGV, SIG_DFL);
94 | signal(SIGFPE, SIG_DFL);
95 | signal(SIGBUS, SIG_DFL);
96 | signal(SIGPIPE, SIG_DFL);
97 |
98 | NSLog(@"%@",[exception name]);
99 | [self logLocalException:exception];
100 |
101 | if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName])
102 | {
103 | kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);
104 | }
105 | else
106 | {
107 | [exception raise];
108 | }
109 | }
110 |
111 | // you can report logs here or store them
112 | -(void)logLocalException:(NSException *)exception {
113 |
114 | NSArray *stackArray = [CrashCatcher backtrace];
115 | NSString *reason = [exception reason];
116 | NSString *name = [exception name];
117 | NSString *exceptionInfo = [NSString stringWithFormat:@"Exception reason:%@\nException name:%@\nException stack:%@\nUserInfo:%@\n",name, reason, stackArray,exception.userInfo];
118 |
119 | NSString *logFilePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject stringByAppendingPathComponent:@"debug_exception_log.txt"];
120 | NSFileManager *manager = [NSFileManager defaultManager];
121 | if(![manager fileExistsAtPath:logFilePath]){
122 | [manager createFileAtPath:logFilePath contents:[exceptionInfo dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
123 | }else{
124 | NSData *data = [NSData dataWithContentsOfFile:logFilePath];
125 | NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
126 | contents = [contents stringByAppendingString:exceptionInfo];
127 | [contents writeToFile:logFilePath atomically:true encoding:NSUTF8StringEncoding error:nil];
128 | }
129 | }
130 |
131 | // stack crash
132 | void catchCrash(NSException *exception) {
133 |
134 | //递增一个全局计数器
135 | int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
136 | if (exceptionCount > UncaughtExceptionMaximum)
137 | {
138 | return;
139 | }
140 |
141 | //渠道回溯的堆栈
142 | NSArray *callStack = [CrashCatcher backtrace];
143 | NSMutableDictionary *userInfo =
144 | [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
145 |
146 | //把堆栈信息存入字典中
147 | [userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];
148 |
149 | [[CrashCatcher sharedInstance]
150 | performSelectorOnMainThread:@selector(handleException:)
151 | withObject:
152 | [NSException
153 | exceptionWithName:[exception name]
154 | reason:[exception reason]
155 | userInfo:userInfo]
156 | waitUntilDone:YES];
157 | }
158 |
159 | // C or C++ API crash signal
160 | void setCrashSignalHandler() {
161 | signal(SIGABRT, receiveSignal);
162 | signal(SIGILL, receiveSignal);
163 | signal(SIGSEGV, receiveSignal);
164 | signal(SIGFPE, receiveSignal);
165 | signal(SIGBUS, receiveSignal);
166 | signal(SIGPIPE, receiveSignal);
167 | }
168 |
169 | void receiveSignal(int signalType) {
170 |
171 | NSString *reason = [NSString stringWithFormat:@"Signal name:%@ \n was raised",[[CrashCatcher sharedInstance] nameOfSignal: signalType]];
172 |
173 | int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
174 | if (exceptionCount > UncaughtExceptionMaximum)
175 | {
176 | return;
177 | }
178 |
179 | NSMutableDictionary *userInfo = @{UncaughtExceptionHandlerSignalKey: @(signalType)}.mutableCopy;
180 |
181 | [userInfo
182 | setObject:[CrashCatcher backtrace]
183 | forKey:UncaughtExceptionHandlerAddressesKey];
184 |
185 | [[CrashCatcher sharedInstance]
186 | performSelectorOnMainThread:@selector(handleException:)
187 | withObject:
188 | [NSException
189 | exceptionWithName:UncaughtExceptionHandlerSignalExceptionName
190 | reason:reason
191 | userInfo:@{UncaughtExceptionHandlerSignalKey: @(signalType)}]
192 | waitUntilDone:YES];
193 |
194 | [[CrashCatcher sharedInstance] killApp];
195 | }
196 |
197 | -(NSString *)nameOfSignal:(int)signalType {
198 | switch (signalType) {
199 | case SIGABRT:
200 | return @"SIGABRT";
201 | break;
202 | case SIGILL:
203 | return @"SIGILL";
204 | break;
205 | case SIGSEGV:
206 | return @"SIGSEGV";
207 | break;
208 | case SIGFPE:
209 | return @"SIGFPE";
210 | break;
211 | case SIGBUS:
212 | return @"SIGBUS";
213 | break;
214 | case SIGPIPE:
215 | return @"SIGPIPE";
216 | break;
217 | default:
218 | return @"OTHER";
219 | break;
220 | }
221 | }
222 |
223 | -(void)killApp {
224 |
225 | NSSetUncaughtExceptionHandler(nil);
226 |
227 | signal(SIGABRT, SIG_DFL);
228 | signal(SIGILL, SIG_DFL);
229 | signal(SIGSEGV, SIG_DFL);
230 | signal(SIGFPE, SIG_DFL);
231 | signal(SIGBUS, SIG_DFL);
232 | signal(SIGPIPE, SIG_DFL);
233 |
234 | kill(getpid(), SIGKILL);
235 | }
236 |
237 | @end
238 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/NSObject+MethodSwizzleList.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MethodSwizzleList.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/29.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSObject (MethodSwizzleList)
12 |
13 | @property (nonatomic, strong) NSArray *swizzleMethodList;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/NSObject+MethodSwizzleList.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MethodSwizzleList.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/29.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "NSObject+MethodSwizzleList.h"
10 | #import
11 |
12 | static const void *methodListKey = &methodListKey;
13 |
14 | @implementation NSObject (MethodSwizzleList)
15 |
16 | -(NSArray *)swizzleMethodList {
17 | return objc_getAssociatedObject(self, methodListKey);
18 | }
19 |
20 | -(void)setSwizzleMethodList:(NSArray *)swizzleMethodList {
21 | objc_setAssociatedObject(self, methodListKey, swizzleMethodList, OBJC_ASSOCIATION_RETAIN);
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/OriginalObjectMethod+Swizzle.h:
--------------------------------------------------------------------------------
1 | //
2 | // OriginalObjectMethod+Swizzle.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "OriginalObjectMethod.h"
10 |
11 | @interface OriginalObjectMethod (Swizzle)
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/OriginalObjectMethod+Swizzle.m:
--------------------------------------------------------------------------------
1 | //
2 | // OriginalObjectMethod+Swizzle.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "OriginalObjectMethod+Swizzle.h"
10 | #import
11 |
12 | @implementation OriginalObjectMethod (Swizzle)
13 |
14 | +(void)load {
15 | Method originalMethod = class_getInstanceMethod(self, @selector(Foo));
16 | Method swizzledMethod = class_getInstanceMethod(self, @selector(swizzle_Foo));
17 | method_exchangeImplementations(originalMethod, swizzledMethod);
18 |
19 | originalMethod = class_getInstanceMethod(self, @selector(Small));
20 | swizzledMethod = class_getInstanceMethod(self, @selector(swizzle_Small));
21 | method_exchangeImplementations(originalMethod, swizzledMethod);
22 | }
23 |
24 | -(void)swizzle_Foo {
25 |
26 | NSLog(@"swizzle func swizzle_Foo");
27 | [self swizzle_Foo];
28 | }
29 |
30 | -(void)swizzle_Small {
31 | NSLog(@"swizzle func swizzle_Small");
32 | [self swizzle_Small];
33 | }
34 |
35 | -(void)write {
36 | NSLog(@"method override in category");
37 | }
38 |
39 | +(void)install {
40 | NSLog(@"override in category");
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/OriginalObjectMethod.h:
--------------------------------------------------------------------------------
1 | //
2 | // OriginalObjectMethod.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface OriginalObjectMethod : NSObject
12 |
13 | -(void)Foo;
14 |
15 | -(void)Small;
16 |
17 | -(void)checkSwizzledMethod;
18 |
19 | +(void)install;
20 |
21 | -(void)write;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/OriginalObjectMethod.m:
--------------------------------------------------------------------------------
1 | //
2 | // OriginalObjectMethod.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "OriginalObjectMethod.h"
10 | #import
11 | #import "method_check.h"
12 | #import "NSObject+MethodSwizzleList.h"
13 |
14 | @implementation OriginalObjectMethod
15 |
16 | +(void)install {
17 | NSLog(@"class func :install");
18 | }
19 |
20 | -(void)Foo {
21 | NSLog(@"original func Foo:");
22 | }
23 |
24 | -(void)Small {
25 | NSLog(@"this is small func");
26 | }
27 |
28 | -(void)write {
29 | NSLog(@"original method write");
30 | }
31 |
32 | -(void)checkSwizzledMethod {
33 | // check method list find out has hooked method
34 |
35 | NSMutableArray *swizzleMethodListArray = @[].mutableCopy;
36 | unsigned int methodCount = 0;
37 | Method *methodList = class_copyMethodList([self class], &methodCount);
38 |
39 | if (methodList) {
40 |
41 | NSLog(@"methodCount:%d",methodCount);
42 |
43 | const char *originalName = NULL;
44 | const char *swizzledMethodList = NULL;
45 | unsigned int swizzledCount = 0;
46 | BOOL validate = validate_methods(NSStringFromClass([self class]).UTF8String, &swizzledMethodList, &originalName, &swizzledCount);
47 |
48 | if (swizzledCount > 0 || !validate) {
49 | if (swizzledMethodList == NULL || originalName == NULL) {
50 | NSLog(@"swizzleNameList:%s,originalNameList:%s",swizzledMethodList, originalName);
51 | return ;
52 | }
53 | NSString *swizzledNameList = [[NSString stringWithUTF8String:swizzledMethodList] stringByReplacingOccurrencesOfString:@"\n\n" withString:@"\n"];
54 | NSString *originalNameList = [[NSString stringWithUTF8String:originalName] stringByReplacingOccurrencesOfString:@"\n\n" withString:@"\n"];
55 | NSArray *swizzledList = [swizzledNameList componentsSeparatedByString:@"\n"];
56 | NSArray *originalList = [originalNameList componentsSeparatedByString:@"\n"];
57 |
58 | for (int i = 0; i < swizzledCount; i ++) {
59 | NSString *methodOriginalName = originalList[i];
60 | NSString *swizzledName = swizzledList[i];
61 | NSMutableDictionary *swizzleInfoDict = @{}.mutableCopy;
62 | swizzleInfoDict[@"originalName"] = methodOriginalName;
63 | swizzleInfoDict[@"swizzledMethodName"] = swizzledName;
64 | [swizzleMethodListArray addObject: swizzleInfoDict];
65 | }
66 | }
67 | self.swizzleMethodList = swizzleMethodListArray;
68 | free(methodList);
69 | }
70 | NSLog(@"swizzledInfo:%@",self.swizzleMethodList);
71 | }
72 |
73 | @end
74 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/fishhook.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Facebook, Inc.
2 | // All rights reserved.
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | // * Redistributions of source code must retain the above copyright notice,
6 | // this list of conditions and the following disclaimer.
7 | // * Redistributions in binary form must reproduce the above copyright notice,
8 | // this list of conditions and the following disclaimer in the documentation
9 | // and/or other materials provided with the distribution.
10 | // * Neither the name Facebook nor the names of its contributors may be used to
11 | // endorse or promote products derived from this software without specific
12 | // prior written permission.
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | #import "fishhook.h"
25 |
26 | #import
27 | #import
28 | #import
29 | #import
30 | #import
31 | #import
32 | #import
33 |
34 | #ifdef __LP64__
35 | typedef struct mach_header_64 mach_header_t;
36 | typedef struct segment_command_64 segment_command_t;
37 | typedef struct section_64 section_t;
38 | typedef struct nlist_64 nlist_t;
39 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64
40 | #else
41 | typedef struct mach_header mach_header_t;
42 | typedef struct segment_command segment_command_t;
43 | typedef struct section section_t;
44 | typedef struct nlist nlist_t;
45 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT
46 | #endif
47 |
48 | #ifndef SEG_DATA_CONST
49 | #define SEG_DATA_CONST "__DATA_CONST"
50 | #endif
51 |
52 | struct rebindings_entry {
53 | struct rebinding *rebindings;
54 | size_t rebindings_nel;
55 | struct rebindings_entry *next;
56 | };
57 |
58 | static struct rebindings_entry *_rebindings_head;
59 |
60 | static int prepend_rebindings(struct rebindings_entry **rebindings_head,
61 | struct rebinding rebindings[],
62 | size_t nel) {
63 | struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry));
64 | if (!new_entry) {
65 | return -1;
66 | }
67 | new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel);
68 | if (!new_entry->rebindings) {
69 | free(new_entry);
70 | return -1;
71 | }
72 | memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel);
73 | new_entry->rebindings_nel = nel;
74 | new_entry->next = *rebindings_head;
75 | *rebindings_head = new_entry;
76 | return 0;
77 | }
78 |
79 | static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
80 | section_t *section,
81 | intptr_t slide,
82 | nlist_t *symtab,
83 | char *strtab,
84 | uint32_t *indirect_symtab) {
85 | uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
86 | void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
87 | for (uint i = 0; i < section->size / sizeof(void *); i++) {
88 | uint32_t symtab_index = indirect_symbol_indices[i];
89 | if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||
90 | symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) {
91 | continue;
92 | }
93 | uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;
94 | char *symbol_name = strtab + strtab_offset;
95 | if (strnlen(symbol_name, 2) < 2) {
96 | continue;
97 | }
98 | struct rebindings_entry *cur = rebindings;
99 | while (cur) {
100 | for (uint j = 0; j < cur->rebindings_nel; j++) {
101 | if (strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {
102 | if (cur->rebindings[j].replaced != NULL &&
103 | indirect_symbol_bindings[i] != cur->rebindings[j].replacement) {
104 | *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i];
105 | }
106 | indirect_symbol_bindings[i] = cur->rebindings[j].replacement;
107 | goto symbol_loop;
108 | }
109 | }
110 | cur = cur->next;
111 | }
112 | symbol_loop:;
113 | }
114 | }
115 |
116 | static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
117 | const struct mach_header *header,
118 | intptr_t slide) {
119 | Dl_info info;
120 | if (dladdr(header, &info) == 0) {
121 | return;
122 | }
123 |
124 | segment_command_t *cur_seg_cmd;
125 | segment_command_t *linkedit_segment = NULL;
126 | struct symtab_command* symtab_cmd = NULL;
127 | struct dysymtab_command* dysymtab_cmd = NULL;
128 |
129 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);
130 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
131 | cur_seg_cmd = (segment_command_t *)cur;
132 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
133 | if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) {
134 | linkedit_segment = cur_seg_cmd;
135 | }
136 | } else if (cur_seg_cmd->cmd == LC_SYMTAB) {
137 | symtab_cmd = (struct symtab_command*)cur_seg_cmd;
138 | } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) {
139 | dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;
140 | }
141 | }
142 |
143 | if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||
144 | !dysymtab_cmd->nindirectsyms) {
145 | return;
146 | }
147 |
148 | // Find base symbol/string table addresses
149 | uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
150 | nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
151 | char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
152 |
153 | // Get indirect symbol table (array of uint32_t indices into symbol table)
154 | uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);
155 |
156 | cur = (uintptr_t)header + sizeof(mach_header_t);
157 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
158 | cur_seg_cmd = (segment_command_t *)cur;
159 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
160 | if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&
161 | strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {
162 | continue;
163 | }
164 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) {
165 | section_t *sect =
166 | (section_t *)(cur + sizeof(segment_command_t)) + j;
167 | if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
168 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
169 | }
170 | if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {
171 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
172 | }
173 | }
174 | }
175 | }
176 | }
177 |
178 | static void _rebind_symbols_for_image(const struct mach_header *header,
179 | intptr_t slide) {
180 | rebind_symbols_for_image(_rebindings_head, header, slide);
181 | }
182 |
183 | int rebind_symbols_image(void *header,
184 | intptr_t slide,
185 | struct rebinding rebindings[],
186 | size_t rebindings_nel) {
187 | struct rebindings_entry *rebindings_head = NULL;
188 | int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
189 | rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
190 | free(rebindings_head);
191 | return retval;
192 | }
193 |
194 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {
195 | int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);
196 | if (retval < 0) {
197 | return retval;
198 | }
199 | // If this was the first call, register callback for image additions (which is also invoked for
200 | // existing images, otherwise, just run on existing images
201 | if (!_rebindings_head->next) {
202 | _dyld_register_func_for_add_image(_rebind_symbols_for_image);
203 | } else {
204 | uint32_t c = _dyld_image_count();
205 | for (uint32_t i = 0; i < c; i++) {
206 | _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
207 | }
208 | }
209 | return retval;
210 | }
211 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/fishhook.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Facebook, Inc.
2 | // All rights reserved.
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | // * Redistributions of source code must retain the above copyright notice,
6 | // this list of conditions and the following disclaimer.
7 | // * Redistributions in binary form must reproduce the above copyright notice,
8 | // this list of conditions and the following disclaimer in the documentation
9 | // and/or other materials provided with the distribution.
10 | // * Neither the name Facebook nor the names of its contributors may be used to
11 | // endorse or promote products derived from this software without specific
12 | // prior written permission.
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | #ifndef fishhook_h
25 | #define fishhook_h
26 |
27 | #include
28 | #include
29 |
30 | #if !defined(FISHHOOK_EXPORT)
31 | #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden")))
32 | #else
33 | #define FISHHOOK_VISIBILITY __attribute__((visibility("default")))
34 | #endif
35 |
36 | #ifdef __cplusplus
37 | extern "C" {
38 | #endif //__cplusplus
39 |
40 | /*
41 | * A structure representing a particular intended rebinding from a symbol
42 | * name to its replacement
43 | */
44 | struct rebinding {
45 | const char *name;
46 | void *replacement;
47 | void **replaced;
48 | };
49 |
50 | /*
51 | * For each rebinding in rebindings, rebinds references to external, indirect
52 | * symbols with the specified name to instead point at replacement for each
53 | * image in the calling process as well as for all future images that are loaded
54 | * by the process. If rebind_functions is called more than once, the symbols to
55 | * rebind are added to the existing list of rebindings, and if a given symbol
56 | * is rebound more than once, the later rebinding will take precedence.
57 | */
58 | FISHHOOK_VISIBILITY
59 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
60 |
61 | /*
62 | * Rebinds as above, but only in the specified image. The header should point
63 | * to the mach-o header, the slide should be the slide offset. Others as above.
64 | */
65 | FISHHOOK_VISIBILITY
66 | int rebind_symbols_image(void *header,
67 | intptr_t slide,
68 | struct rebinding rebindings[],
69 | size_t rebindings_nel);
70 |
71 | #ifdef __cplusplus
72 | }
73 | #endif //__cplusplus
74 |
75 | #endif //fishhook_h
76 |
77 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/method_check.c:
--------------------------------------------------------------------------------
1 | //
2 | // method_check.c
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #include "method_check.h"
10 |
--------------------------------------------------------------------------------
/cpapm/APM/CrashANT/method_check.h:
--------------------------------------------------------------------------------
1 | //
2 | // method_check.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #ifndef method_check_h
10 | #define method_check_h
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | // find out which method was hooked
21 | static inline BOOL validate_methods(const char *cls,const char **swizzleName, const char **originalName, unsigned int *swizzledMethodCount) __attribute__ ((always_inline));
22 |
23 | static inline const char *join(const char *, const char *) __attribute__ ((always_inline));
24 | static inline const char *joinWithoutSpace(const char *, const char *) __attribute__ ((always_inline));
25 |
26 | BOOL validate_methods(const char *cls,const char **swizzleName, const char **originalName, unsigned int *swizzledMethodCount){
27 | Class aClass = objc_getClass(cls);
28 | Method *methods;
29 | unsigned int nMethods;
30 | Dl_info info;
31 | IMP imp;
32 | char buf[128];
33 | Method m;
34 | const char *swizzledMethodNameList = NULL;
35 | const char *swizzledOriginalMethodNameList = NULL;
36 | unsigned int swizzledCount = 0;
37 |
38 | if(!aClass)
39 | return NO;
40 | methods = class_copyMethodList(aClass, &nMethods);
41 | while (nMethods--) {
42 | m = methods[nMethods];
43 | printf("validating [%s %s]\n",(const char *)class_getName(aClass), sel_getName(method_getName(m)));
44 | const char *function_name = sel_getName(method_getName(m));
45 | imp = method_getImplementation(m);
46 | //imp = class_getMethodImplementation(aClass, sel_registerName("allObjects"));
47 | if(!imp){
48 | printf("error:method_getImplementation(%s) failed\n",sel_getName(method_getName(m)));
49 | free(methods);
50 | return NO;
51 | }
52 |
53 | if(!dladdr(imp, &info)){
54 | printf("error:dladdr() failed for %s\n",sel_getName(method_getName(m)));
55 | free(methods);
56 | return NO;
57 | }
58 |
59 |
60 | const char *func_type = "-[";
61 | char type[] = "-";
62 | if (info.dli_sname) {
63 | strncpy(type, info.dli_sname, 1);
64 | if (strcmp(type, "+") == 0) {
65 | func_type = "+[";
66 | }else if (strcmp(type, "-") == 0){
67 | func_type = "-[";
68 | }else{
69 | printf("method:%s not class func also not instance",function_name);
70 | }
71 | }
72 |
73 | /*formate method*/
74 | const char *dli_function_name = joinWithoutSpace("-[", class_getName(aClass));
75 | dli_function_name = joinWithoutSpace(dli_function_name, " ");
76 | dli_function_name = joinWithoutSpace(dli_function_name, function_name);
77 | dli_function_name = joinWithoutSpace(dli_function_name, "]");
78 |
79 | if(strcmp(info.dli_sname, dli_function_name)){
80 | swizzledCount = swizzledCount + 1;
81 | swizzledOriginalMethodNameList = join(swizzledOriginalMethodNameList, function_name);
82 | swizzledMethodNameList = join(swizzledMethodNameList, info.dli_sname);
83 | continue;
84 | }
85 | if (info.dli_sname != NULL && strcmp(info.dli_sname, "") != 0) {
86 | /*Validate class name in symbol*/
87 | snprintf(buf, sizeof(buf), "[%s ",(const char *) class_getName(aClass));
88 | if(strncmp(info.dli_sname + 1, buf, strlen(buf))){
89 | snprintf(buf, sizeof(buf),"[%s(",(const char *)class_getName(aClass));
90 | if(strncmp(info.dli_sname + 1, buf, strlen(buf))){
91 | swizzledCount = swizzledCount + 1;
92 | swizzledOriginalMethodNameList = join(swizzledOriginalMethodNameList, function_name);
93 | swizzledMethodNameList = join(swizzledMethodNameList, info.dli_sname);
94 | continue;
95 | }
96 | }
97 |
98 | /*Validate selector in symbol*/
99 | snprintf(buf, sizeof(buf), " %s]",(const char*)sel_getName(method_getName(m)));
100 | if(strncmp(info.dli_sname + (strlen(info.dli_sname) - strlen(buf)), buf, strlen(buf))){
101 | swizzledCount = swizzledCount + 1;
102 | swizzledOriginalMethodNameList = join(swizzledOriginalMethodNameList, function_name);
103 | swizzledMethodNameList = join(swizzledMethodNameList, info.dli_sname);
104 | continue;
105 | }
106 | }else{
107 | printf(" \n");
108 | }
109 | }
110 |
111 | free(methods);
112 | *swizzledMethodCount = swizzledCount;
113 | *swizzleName = swizzledMethodNameList;
114 | *originalName = swizzledOriginalMethodNameList;
115 | return YES;
116 | }
117 |
118 | const char* join(const char *s1, const char *s2)
119 | {
120 | if (s1 == NULL) {
121 | char *result = malloc(strlen(s2)+1);
122 | strcpy(result, s2);
123 | return result;
124 | }
125 | const char *separator = "\n";
126 | char *result = malloc(strlen(s1)+ strlen(separator) +strlen(s2)+1);
127 | if (result == NULL) exit (1);
128 |
129 | strcpy(result, s1);
130 | strcat(result, separator);
131 | strcat(result, s2);
132 |
133 | return result;
134 | }
135 |
136 | const char* joinWithoutSpace(const char *s1, const char *s2)
137 | {
138 | if (s1 == NULL) {
139 | char *result = malloc(strlen(s2)+1);
140 | strcpy(result, s2);
141 | return result;
142 | }
143 | char *result = malloc(strlen(s1)+strlen(s2)+1);
144 | if (result == NULL) exit (1);
145 |
146 | strcpy(result, s1);
147 | strcat(result, s2);
148 |
149 | return result;
150 | }
151 |
152 | #endif /* method_check_h */
153 |
--------------------------------------------------------------------------------
/cpapm/APM/Dependency/Backtrace/BSBacktraceLogger.h:
--------------------------------------------------------------------------------
1 | //
2 | // BSBacktraceLogger.h
3 | // BSBacktraceLogger
4 | //
5 | // Created by 张星宇 on 16/8/27.
6 | // Copyright © 2016年 bestswifter. All rights reserved.
7 | //
8 |
9 | #import
10 | #include
11 | #import
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #define BSLOG NSLog(@"%@",[BSBacktraceLogger bs_backtraceOfCurrentThread]);
20 | #define BSLOG_MAIN NSLog(@"%@",[BSBacktraceLogger bs_backtraceOfMainThread]);
21 | #define BSLOG_ALL NSLog(@"%@",[BSBacktraceLogger bs_backtraceOfAllThread]);
22 |
23 |
24 | @interface BSBacktraceLogger : NSObject
25 |
26 | + (NSString *)bs_backtraceOfAllThread;
27 | + (NSString *)bs_backtraceOfCurrentThread;
28 | + (NSString *)bs_backtraceOfMainThread;
29 | + (NSString *)bs_backtraceOfNSThread:(NSThread *)thread;
30 |
31 | NSString *_bs_backtraceOfThread(thread_t thread);
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/cpapm/APM/Dependency/Backtrace/BSBacktraceLogger.m:
--------------------------------------------------------------------------------
1 | //
2 | // BSBacktraceLogger.m
3 | // BSBacktraceLogger
4 | //
5 | // Created by 张星宇 on 16/8/27.
6 | // Copyright © 2016年 bestswifter. All rights reserved.
7 | //
8 |
9 | #import "BSBacktraceLogger.h"
10 |
11 | #pragma -mark DEFINE MACRO FOR DIFFERENT CPU ARCHITECTURE
12 | #if defined(__arm64__)
13 | #define DETAG_INSTRUCTION_ADDRESS(A) ((A) & ~(3UL))
14 | #define BS_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT
15 | #define BS_THREAD_STATE ARM_THREAD_STATE64
16 | #define BS_FRAME_POINTER __fp
17 | #define BS_STACK_POINTER __sp
18 | #define BS_INSTRUCTION_ADDRESS __pc
19 |
20 | #elif defined(__arm__)
21 | #define DETAG_INSTRUCTION_ADDRESS(A) ((A) & ~(1UL))
22 | #define BS_THREAD_STATE_COUNT ARM_THREAD_STATE_COUNT
23 | #define BS_THREAD_STATE ARM_THREAD_STATE
24 | #define BS_FRAME_POINTER __r[7]
25 | #define BS_STACK_POINTER __sp
26 | #define BS_INSTRUCTION_ADDRESS __pc
27 |
28 | #elif defined(__x86_64__)
29 | #define DETAG_INSTRUCTION_ADDRESS(A) (A)
30 | #define BS_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
31 | #define BS_THREAD_STATE x86_THREAD_STATE64
32 | #define BS_FRAME_POINTER __rbp
33 | #define BS_STACK_POINTER __rsp
34 | #define BS_INSTRUCTION_ADDRESS __rip
35 |
36 | #elif defined(__i386__)
37 | #define DETAG_INSTRUCTION_ADDRESS(A) (A)
38 | #define BS_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
39 | #define BS_THREAD_STATE x86_THREAD_STATE32
40 | #define BS_FRAME_POINTER __ebp
41 | #define BS_STACK_POINTER __esp
42 | #define BS_INSTRUCTION_ADDRESS __eip
43 |
44 | #endif
45 |
46 | #define CALL_INSTRUCTION_FROM_RETURN_ADDRESS(A) (DETAG_INSTRUCTION_ADDRESS((A)) - 1)
47 |
48 | #if defined(__LP64__)
49 | #define TRACE_FMT "%-4d%-31s 0x%016lx %s + %lu"
50 | #define POINTER_FMT "0x%016lx"
51 | #define POINTER_SHORT_FMT "0x%lx"
52 | #define BS_NLIST struct nlist_64
53 | #else
54 | #define TRACE_FMT "%-4d%-31s 0x%08lx %s + %lu"
55 | #define POINTER_FMT "0x%08lx"
56 | #define POINTER_SHORT_FMT "0x%lx"
57 | #define BS_NLIST struct nlist
58 | #endif
59 |
60 | typedef struct BSStackFrameEntry{
61 | const struct BSStackFrameEntry *const previous;
62 | const uintptr_t return_address;
63 | } BSStackFrameEntry;
64 |
65 | static mach_port_t main_thread_id;
66 |
67 | @implementation BSBacktraceLogger
68 |
69 | + (void)load {
70 | main_thread_id = mach_thread_self();
71 | }
72 |
73 | #pragma -mark Implementation of interface
74 | + (NSString *)bs_backtraceOfNSThread:(NSThread *)thread {
75 | return _bs_backtraceOfThread(bs_machThreadFromNSThread(thread));
76 | }
77 |
78 | + (NSString *)bs_backtraceOfCurrentThread {
79 | return [self bs_backtraceOfNSThread:[NSThread currentThread]];
80 | }
81 |
82 | + (NSString *)bs_backtraceOfMainThread {
83 | return [self bs_backtraceOfNSThread:[NSThread mainThread]];
84 | }
85 |
86 | + (NSString *)bs_backtraceOfAllThread {
87 | thread_act_array_t threads;
88 | mach_msg_type_number_t thread_count = 0;
89 | const task_t this_task = mach_task_self();
90 |
91 | kern_return_t kr = task_threads(this_task, &threads, &thread_count);
92 | if(kr != KERN_SUCCESS) {
93 | return @"Fail to get information of all threads";
94 | }
95 |
96 | NSMutableString *resultString = [NSMutableString stringWithFormat:@"Call Backtrace of %u threads:\n", thread_count];
97 | for(int i = 0; i < thread_count; i++) {
98 | [resultString appendString:_bs_backtraceOfThread(threads[i])];
99 | }
100 | return [resultString copy];
101 | }
102 |
103 | #pragma -mark Get call backtrace of a mach_thread
104 | NSString *_bs_backtraceOfThread(thread_t thread) {
105 | uintptr_t backtraceBuffer[50];
106 | int i = 0;
107 | NSMutableString *resultString = [[NSMutableString alloc] initWithFormat:@"Backtrace of Thread %u:\n", thread];
108 |
109 | _STRUCT_MCONTEXT machineContext;
110 | if(!bs_fillThreadStateIntoMachineContext(thread, &machineContext)) {
111 | return [NSString stringWithFormat:@"Fail to get information about thread: %u", thread];
112 | }
113 |
114 | const uintptr_t instructionAddress = bs_mach_instructionAddress(&machineContext);
115 | backtraceBuffer[i] = instructionAddress;
116 | ++i;
117 |
118 | uintptr_t linkRegister = bs_mach_linkRegister(&machineContext);
119 | if (linkRegister) {
120 | backtraceBuffer[i] = linkRegister;
121 | i++;
122 | }
123 |
124 | if(instructionAddress == 0) {
125 | return @"Fail to get instruction address";
126 | }
127 |
128 | BSStackFrameEntry frame = {0};
129 | const uintptr_t framePtr = bs_mach_framePointer(&machineContext);
130 | if(framePtr == 0 ||
131 | bs_mach_copyMem((void *)framePtr, &frame, sizeof(frame)) != KERN_SUCCESS) {
132 | return @"Fail to get frame pointer";
133 | }
134 |
135 | for(; i < 50; i++) {
136 | backtraceBuffer[i] = frame.return_address;
137 | if(backtraceBuffer[i] == 0 ||
138 | frame.previous == 0 ||
139 | bs_mach_copyMem(frame.previous, &frame, sizeof(frame)) != KERN_SUCCESS) {
140 | break;
141 | }
142 | }
143 |
144 | int backtraceLength = i;
145 | Dl_info symbolicated[backtraceLength];
146 | bs_symbolicate(backtraceBuffer, symbolicated, backtraceLength, 0);
147 | for (int i = 0; i < backtraceLength; ++i) {
148 | [resultString appendFormat:@"%@", bs_logBacktraceEntry(i, backtraceBuffer[i], &symbolicated[i])];
149 | }
150 | [resultString appendFormat:@"\n"];
151 | return [resultString copy];
152 | }
153 |
154 | #pragma -mark Convert NSThread to Mach thread
155 | thread_t bs_machThreadFromNSThread(NSThread *nsthread) {
156 | char name[256];
157 | mach_msg_type_number_t count;
158 | thread_act_array_t list;
159 | task_threads(mach_task_self(), &list, &count);
160 |
161 | NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970];
162 | NSString *originName = [nsthread name];
163 | [nsthread setName:[NSString stringWithFormat:@"%f", currentTimestamp]];
164 |
165 | if ([nsthread isMainThread]) {
166 | return (thread_t)main_thread_id;
167 | }
168 |
169 | for (int i = 0; i < count; ++i) {
170 | pthread_t pt = pthread_from_mach_thread_np(list[i]);
171 | if ([nsthread isMainThread]) {
172 | if (list[i] == main_thread_id) {
173 | return list[i];
174 | }
175 | }
176 | if (pt) {
177 | name[0] = '\0';
178 | pthread_getname_np(pt, name, sizeof name);
179 | if (!strcmp(name, [nsthread name].UTF8String)) {
180 | [nsthread setName:originName];
181 | return list[i];
182 | }
183 | }
184 | }
185 |
186 | [nsthread setName:originName];
187 | return mach_thread_self();
188 | }
189 |
190 | #pragma -mark GenerateBacbsrackEnrty
191 | NSString* bs_logBacktraceEntry(const int entryNum,
192 | const uintptr_t address,
193 | const Dl_info* const dlInfo) {
194 | char faddrBuff[20];
195 | char saddrBuff[20];
196 |
197 | const char* fname = bs_lastPathEntry(dlInfo->dli_fname);
198 | if(fname == NULL) {
199 | sprintf(faddrBuff, POINTER_FMT, (uintptr_t)dlInfo->dli_fbase);
200 | fname = faddrBuff;
201 | }
202 |
203 | uintptr_t offset = address - (uintptr_t)dlInfo->dli_saddr;
204 | const char* sname = dlInfo->dli_sname;
205 | if(sname == NULL) {
206 | sprintf(saddrBuff, POINTER_SHORT_FMT, (uintptr_t)dlInfo->dli_fbase);
207 | sname = saddrBuff;
208 | offset = address - (uintptr_t)dlInfo->dli_fbase;
209 | }
210 | return [NSString stringWithFormat:@"%-30s 0x%08" PRIxPTR " %s + %lu\n" ,fname, (uintptr_t)address, sname, offset];
211 | }
212 |
213 | const char* bs_lastPathEntry(const char* const path) {
214 | if(path == NULL) {
215 | return NULL;
216 | }
217 |
218 | char* lastFile = strrchr(path, '/');
219 | return lastFile == NULL ? path : lastFile + 1;
220 | }
221 |
222 | #pragma -mark HandleMachineContext
223 | bool bs_fillThreadStateIntoMachineContext(thread_t thread, _STRUCT_MCONTEXT *machineContext) {
224 | mach_msg_type_number_t state_count = BS_THREAD_STATE_COUNT;
225 | kern_return_t kr = thread_get_state(thread, BS_THREAD_STATE, (thread_state_t)&machineContext->__ss, &state_count);
226 | return (kr == KERN_SUCCESS);
227 | }
228 |
229 | uintptr_t bs_mach_framePointer(mcontext_t const machineContext){
230 | return machineContext->__ss.BS_FRAME_POINTER;
231 | }
232 |
233 | uintptr_t bs_mach_stackPointer(mcontext_t const machineContext){
234 | return machineContext->__ss.BS_STACK_POINTER;
235 | }
236 |
237 | uintptr_t bs_mach_instructionAddress(mcontext_t const machineContext){
238 | return machineContext->__ss.BS_INSTRUCTION_ADDRESS;
239 | }
240 |
241 | uintptr_t bs_mach_linkRegister(mcontext_t const machineContext){
242 | #if defined(__i386__) || defined(__x86_64__)
243 | return 0;
244 | #else
245 | return machineContext->__ss.__lr;
246 | #endif
247 | }
248 |
249 | kern_return_t bs_mach_copyMem(const void *const src, void *const dst, const size_t numBytes){
250 | vm_size_t bytesCopied = 0;
251 | return vm_read_overwrite(mach_task_self(), (vm_address_t)src, (vm_size_t)numBytes, (vm_address_t)dst, &bytesCopied);
252 | }
253 |
254 | #pragma -mark Symbolicate
255 | void bs_symbolicate(const uintptr_t* const backtraceBuffer,
256 | Dl_info* const symbolsBuffer,
257 | const int numEntries,
258 | const int skippedEntries){
259 | int i = 0;
260 |
261 | if(!skippedEntries && i < numEntries) {
262 | bs_dladdr(backtraceBuffer[i], &symbolsBuffer[i]);
263 | i++;
264 | }
265 |
266 | for(; i < numEntries; i++) {
267 | bs_dladdr(CALL_INSTRUCTION_FROM_RETURN_ADDRESS(backtraceBuffer[i]), &symbolsBuffer[i]);
268 | }
269 | }
270 |
271 | bool bs_dladdr(const uintptr_t address, Dl_info* const info) {
272 | info->dli_fname = NULL;
273 | info->dli_fbase = NULL;
274 | info->dli_sname = NULL;
275 | info->dli_saddr = NULL;
276 |
277 | const uint32_t idx = bs_imageIndexContainingAddress(address);
278 | if(idx == UINT_MAX) {
279 | return false;
280 | }
281 | const struct mach_header* header = _dyld_get_image_header(idx);
282 | const uintptr_t imageVMAddrSlide = (uintptr_t)_dyld_get_image_vmaddr_slide(idx);
283 | const uintptr_t addressWithSlide = address - imageVMAddrSlide;
284 | const uintptr_t segmentBase = bs_segmentBaseOfImageIndex(idx) + imageVMAddrSlide;
285 | if(segmentBase == 0) {
286 | return false;
287 | }
288 |
289 | info->dli_fname = _dyld_get_image_name(idx);
290 | info->dli_fbase = (void*)header;
291 |
292 | // Find symbol tables and get whichever symbol is closest to the address.
293 | const BS_NLIST* bestMatch = NULL;
294 | uintptr_t bestDistance = ULONG_MAX;
295 | uintptr_t cmdPtr = bs_firstCmdAfterHeader(header);
296 | if(cmdPtr == 0) {
297 | return false;
298 | }
299 | for(uint32_t iCmd = 0; iCmd < header->ncmds; iCmd++) {
300 | const struct load_command* loadCmd = (struct load_command*)cmdPtr;
301 | if(loadCmd->cmd == LC_SYMTAB) {
302 | const struct symtab_command* symtabCmd = (struct symtab_command*)cmdPtr;
303 | const BS_NLIST* symbolTable = (BS_NLIST*)(segmentBase + symtabCmd->symoff);
304 | const uintptr_t stringTable = segmentBase + symtabCmd->stroff;
305 |
306 | for(uint32_t iSym = 0; iSym < symtabCmd->nsyms; iSym++) {
307 | // If n_value is 0, the symbol refers to an external object.
308 | if(symbolTable[iSym].n_value != 0) {
309 | uintptr_t symbolBase = symbolTable[iSym].n_value;
310 | uintptr_t currentDistance = addressWithSlide - symbolBase;
311 | if((addressWithSlide >= symbolBase) &&
312 | (currentDistance <= bestDistance)) {
313 | bestMatch = symbolTable + iSym;
314 | bestDistance = currentDistance;
315 | }
316 | }
317 | }
318 | if(bestMatch != NULL) {
319 | info->dli_saddr = (void*)(bestMatch->n_value + imageVMAddrSlide);
320 | info->dli_sname = (char*)((intptr_t)stringTable + (intptr_t)bestMatch->n_un.n_strx);
321 | if(*info->dli_sname == '_') {
322 | info->dli_sname++;
323 | }
324 | // This happens if all symbols have been stripped.
325 | if(info->dli_saddr == info->dli_fbase && bestMatch->n_type == 3) {
326 | info->dli_sname = NULL;
327 | }
328 | break;
329 | }
330 | }
331 | cmdPtr += loadCmd->cmdsize;
332 | }
333 | return true;
334 | }
335 |
336 | uintptr_t bs_firstCmdAfterHeader(const struct mach_header* const header) {
337 | switch(header->magic) {
338 | case MH_MAGIC:
339 | case MH_CIGAM:
340 | return (uintptr_t)(header + 1);
341 | case MH_MAGIC_64:
342 | case MH_CIGAM_64:
343 | return (uintptr_t)(((struct mach_header_64*)header) + 1);
344 | default:
345 | return 0; // Header is corrupt
346 | }
347 | }
348 |
349 | uint32_t bs_imageIndexContainingAddress(const uintptr_t address) {
350 | const uint32_t imageCount = _dyld_image_count();
351 | const struct mach_header* header = 0;
352 |
353 | for(uint32_t iImg = 0; iImg < imageCount; iImg++) {
354 | header = _dyld_get_image_header(iImg);
355 | if(header != NULL) {
356 | // Look for a segment command with this address within its range.
357 | uintptr_t addressWSlide = address - (uintptr_t)_dyld_get_image_vmaddr_slide(iImg);
358 | uintptr_t cmdPtr = bs_firstCmdAfterHeader(header);
359 | if(cmdPtr == 0) {
360 | continue;
361 | }
362 | for(uint32_t iCmd = 0; iCmd < header->ncmds; iCmd++) {
363 | const struct load_command* loadCmd = (struct load_command*)cmdPtr;
364 | if(loadCmd->cmd == LC_SEGMENT) {
365 | const struct segment_command* segCmd = (struct segment_command*)cmdPtr;
366 | if(addressWSlide >= segCmd->vmaddr &&
367 | addressWSlide < segCmd->vmaddr + segCmd->vmsize) {
368 | return iImg;
369 | }
370 | }
371 | else if(loadCmd->cmd == LC_SEGMENT_64) {
372 | const struct segment_command_64* segCmd = (struct segment_command_64*)cmdPtr;
373 | if(addressWSlide >= segCmd->vmaddr &&
374 | addressWSlide < segCmd->vmaddr + segCmd->vmsize) {
375 | return iImg;
376 | }
377 | }
378 | cmdPtr += loadCmd->cmdsize;
379 | }
380 | }
381 | }
382 | return UINT_MAX;
383 | }
384 |
385 | uintptr_t bs_segmentBaseOfImageIndex(const uint32_t idx) {
386 | const struct mach_header* header = _dyld_get_image_header(idx);
387 |
388 | // Look for a segment command and return the file image address.
389 | uintptr_t cmdPtr = bs_firstCmdAfterHeader(header);
390 | if(cmdPtr == 0) {
391 | return 0;
392 | }
393 | for(uint32_t i = 0;i < header->ncmds; i++) {
394 | const struct load_command* loadCmd = (struct load_command*)cmdPtr;
395 | if(loadCmd->cmd == LC_SEGMENT) {
396 | const struct segment_command* segmentCmd = (struct segment_command*)cmdPtr;
397 | if(strcmp(segmentCmd->segname, SEG_LINKEDIT) == 0) {
398 | return segmentCmd->vmaddr - segmentCmd->fileoff;
399 | }
400 | }
401 | else if(loadCmd->cmd == LC_SEGMENT_64) {
402 | const struct segment_command_64* segmentCmd = (struct segment_command_64*)cmdPtr;
403 | if(strcmp(segmentCmd->segname, SEG_LINKEDIT) == 0) {
404 | return (uintptr_t)(segmentCmd->vmaddr - segmentCmd->fileoff);
405 | }
406 | }
407 | cmdPtr += loadCmd->cmdsize;
408 | }
409 | return 0;
410 | }
411 |
412 | @end
413 |
--------------------------------------------------------------------------------
/cpapm/APM/Dependency/Backtrace/WTBacktrace.h:
--------------------------------------------------------------------------------
1 | //
2 | // WTBacktrace.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 | #include
11 |
12 | @interface WTBacktrace : NSObject
13 |
14 | +(NSString *)withThread:(NSThread *)thread;
15 | +(NSString *)currentThread;
16 | +(NSString *)mainThread;
17 | +(NSString *)allThread;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/cpapm/APM/Dependency/Backtrace/WTBacktrace.m:
--------------------------------------------------------------------------------
1 | //
2 | // WTBacktrace.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "WTBacktrace.h"
10 | #import "BSBacktraceLogger.h"
11 | #import
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | @implementation WTBacktrace
21 |
22 | +(NSString *)withThread:(NSThread *)thread {
23 | return [BSBacktraceLogger bs_backtraceOfNSThread:thread];
24 | }
25 |
26 | +(NSString *)currentThread {
27 | return [self withThread:[NSThread currentThread]];
28 | }
29 |
30 | +(NSString *)mainThread {
31 | return [self withThread:[NSThread mainThread]];
32 | }
33 |
34 | +(NSString *)allThread {
35 |
36 | thread_act_array_t threads = nil;
37 | mach_msg_type_number_t thread_count = 0;
38 | if (task_threads(mach_task_self_, &(threads), &thread_count) != KERN_SUCCESS) {
39 | return @"";
40 | }
41 |
42 | NSString *resultString = [NSString stringWithFormat:@"Call Backtrace of %d threads:\n", thread_count];
43 |
44 | for (int i = 0; i < thread_count; i++) {
45 | NSInteger index = i;
46 | NSString *bt = _bs_backtraceOfThread(threads[index]);
47 | resultString = [resultString stringByAppendingString:bt];
48 | }
49 | return resultString;
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/DetectorProtocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // DetectorProtocol.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @protocol DetectorProtocol
12 |
13 | +(void)prepareForDetector;
14 |
15 | -(BOOL)markAlive;
16 |
17 | -(BOOL)isAlive;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/NSObject+Detector.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+Detector.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "DetectorProtocol.h"
11 | #import "WTObjectProxy.h"
12 |
13 | @interface NSObject (Detector)
14 |
15 | + (void)swizzleMethod:(SEL)originalMethod withMethod:(SEL)targetMethod;
16 |
17 | @property (nonatomic, strong) WTObjectProxy *wtproxy;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/NSObject+Detector.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+Detector.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "NSObject+Detector.h"
10 | #import
11 | #import
12 |
13 | @implementation NSObject (Detector)
14 |
15 | +(void)swizzleMethod:(SEL)originalMethod withMethod:(SEL)targetMethod {
16 |
17 | // check has hooked then hook the hooked method
18 |
19 | Class class = [self class];
20 |
21 | Method originalM = class_getInstanceMethod(class, originalMethod);
22 | Method swizzledM = class_getInstanceMethod(class, targetMethod);
23 |
24 | BOOL didAddMethod =
25 | class_addMethod(class,
26 | originalMethod,
27 | method_getImplementation(swizzledM),
28 | method_getTypeEncoding(swizzledM));
29 |
30 | if (didAddMethod) {
31 | class_replaceMethod(class,
32 | targetMethod,
33 | method_getImplementation(originalM),
34 | method_getTypeEncoding(originalM));
35 | }else{
36 | method_exchangeImplementations(originalM, swizzledM);
37 | }
38 |
39 | }
40 |
41 | @dynamic wtproxy;
42 | -(void)setWtproxy:(WTObjectProxy *)wtproxy {
43 | objc_setAssociatedObject(self, sel_getName(@selector(wtproxy)), wtproxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
44 | }
45 |
46 | -(WTObjectProxy *)wtproxy {
47 | return objc_getAssociatedObject(self, sel_getName(@selector(wtproxy)));
48 | }
49 |
50 | + (void)prepareForSniffer {
51 |
52 | }
53 |
54 | -(BOOL)isAlive {
55 | return true;
56 | }
57 |
58 | -(BOOL)markAlive {
59 | if (self.wtproxy != nil) {
60 | return false;
61 | }
62 |
63 | //skip system class
64 | NSString* className = NSStringFromClass([self class]);
65 | if ([className hasPrefix:@"_"] || [className hasPrefix:@"UI"] || [className hasPrefix:@"NS"]) {
66 | return false;
67 | }
68 |
69 | //view object needs a super view to be alive
70 | if ([self isKindOfClass:[UIView class]]) {
71 | UIView* v = (UIView*)self;
72 | if (v.superview == nil) {
73 | return false;
74 | }
75 | }
76 |
77 | //controller object needs a parent to be alive
78 | if ([self isKindOfClass:[UIViewController class]]) {
79 | UIViewController* c = (UIViewController*)self;
80 | if (c.navigationController == nil && c.presentingViewController == nil) {
81 | return false;
82 | }
83 | }
84 |
85 | //skip some weird system classes
86 | static NSMutableDictionary* ignoreList = nil;
87 | @synchronized (self) {
88 | if (ignoreList == nil) {
89 | ignoreList = @{}.mutableCopy;
90 | NSArray* arr = @[@"UITextFieldLabel", @"UIFieldEditor", @"UITextSelectionView",
91 | @"UITableViewCellSelectedBackground", @"UIView", @"UIAlertController"];
92 | for (NSString* str in arr) {
93 | ignoreList[str] = @":)";
94 | }
95 | }
96 | if ([ignoreList objectForKey:NSStringFromClass([self class])]) {
97 | return false;
98 | }
99 | }
100 |
101 | WTObjectProxy *proxy = [WTObjectProxy new];
102 | self.wtproxy = proxy;
103 | [self.wtproxy prepareProxy:self];
104 | return true;
105 | }
106 |
107 | @end
108 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/UINavigationController+Detector.h:
--------------------------------------------------------------------------------
1 | //
2 | // UINavigationController+Detector.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UINavigationController (Detector)
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/UINavigationController+Detector.m:
--------------------------------------------------------------------------------
1 | //
2 | // UINavigationController+Detector.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "UINavigationController+Detector.h"
10 | #import
11 | #import "NSObject+Detector.h"
12 |
13 | @implementation UINavigationController (Detector)
14 |
15 | +(void)prepareForDetector {
16 | static dispatch_once_t onceToken;
17 | dispatch_once(&onceToken, ^{
18 | [self swizzleMethod:@selector(pushViewController:animated:) withMethod:@selector(swizzled_pushViewController:animated:)];
19 | });
20 | }
21 |
22 | - (void)swizzled_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
23 |
24 | [self swizzled_pushViewController:viewController animated:animated];
25 |
26 | [viewController markAlive];
27 |
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/UIView+Detector.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Detector.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIView (Detector)
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/UIView+Detector.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Detector.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "UIView+Detector.h"
10 | #import
11 | #import "NSObject+Detector.h"
12 |
13 | @implementation UIView (Detector)
14 |
15 | +(void)prepareForDetector {
16 | static dispatch_once_t onceToken;
17 | dispatch_once(&onceToken, ^{
18 | [self swizzleMethod:@selector(didMoveToSuperview) withMethod:@selector(swizzled_didMoveToSuperview)];
19 | });
20 | }
21 |
22 | - (void)swizzled_didMoveToSuperview
23 | {
24 | [self swizzled_didMoveToSuperview];
25 |
26 | BOOL hasAliveParent = false;
27 |
28 | UIResponder* r = self.nextResponder;
29 | while (r) {
30 | if ([r wtproxy] != nil) {
31 | hasAliveParent = true;
32 | break;
33 | }
34 | r = r.nextResponder;
35 | }
36 |
37 | if (hasAliveParent) {
38 | [self markAlive];
39 | }
40 | }
41 |
42 | - (BOOL)isAlive
43 | {
44 | BOOL alive = true;
45 |
46 | BOOL onUIStack = false;
47 |
48 | UIView* v = self;
49 | while (v.superview != nil) {
50 | v = v.superview;
51 | }
52 | if ([v isKindOfClass:[UIWindow class]]) {
53 | onUIStack = true;
54 | }
55 |
56 | //save responder
57 | if (self.wtproxy.weakResponder == nil) {
58 | UIResponder* r = self.nextResponder;
59 | while (r) {
60 |
61 | if (r.nextResponder == nil) {
62 | break;
63 | }else{
64 | r = r.nextResponder;
65 | }
66 |
67 | if ([r isKindOfClass:[UIViewController class]]) {
68 | break;
69 | }
70 | }
71 | self.wtproxy.weakResponder = r;
72 | }
73 |
74 | if (onUIStack == false) {
75 | alive = false;
76 |
77 | //if controller is active, view should be considered alive too
78 | if ([self.wtproxy.weakResponder isKindOfClass:[UIViewController class]]) {
79 | alive = true;
80 | }
81 | }
82 |
83 | return alive;
84 | }
85 |
86 |
87 | @end
88 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/UIViewController+Detector.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Detector.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIViewController (Detector)
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/UIViewController+Detector.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Detector.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "UIViewController+Detector.h"
10 | #import "NSObject+Detector.h"
11 | #import
12 |
13 | @implementation UIViewController (Detector)
14 |
15 | +(void)prepareForDetector {
16 |
17 | static dispatch_once_t onceToken;
18 | dispatch_once(&onceToken, ^{
19 | [self swizzleMethod:@selector(presentViewController:animated:completion:) withMethod:@selector(swizzled_presentViewController:animated:completion:)];
20 | });
21 | }
22 |
23 | - (void)swizzled_presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion {
24 | [self swizzled_presentViewController:viewControllerToPresent animated:flag completion:completion];
25 |
26 | [viewControllerToPresent markAlive];
27 | }
28 |
29 | - (BOOL)isAlive
30 | {
31 | BOOL alive = true;
32 |
33 | BOOL visibleOnScreen = false;
34 |
35 | UIView* v = self.view;
36 | while (v.superview != nil) {
37 | v = v.superview;
38 | }
39 | if ([v isKindOfClass:[UIWindow class]]) {
40 | visibleOnScreen = true;
41 | }
42 |
43 |
44 | BOOL beingHeld = false;
45 | if (self.navigationController != nil || self.presentingViewController != nil) {
46 | beingHeld = true;
47 | }
48 |
49 | //not visible, not in view stack
50 | if (visibleOnScreen == false && beingHeld == false) {
51 | alive = false;
52 | }
53 |
54 | return alive;
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/WTLeaksDetector.h:
--------------------------------------------------------------------------------
1 | //
2 | // WTLeaksDetector.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #define Notif_WTDetector_Ping @"Notif_WTDetector_Ping"
12 | #define Notif_WTDetector_Pong @"Notif_WTDetector_Pong"
13 |
14 | @interface WTLeaksDetector : NSObject
15 |
16 | + (instancetype)sharedInstance;
17 |
18 | -(void)startDetector;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/WTLeaksDetector.m:
--------------------------------------------------------------------------------
1 | //
2 | // WTLeaksDetector.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "WTLeaksDetector.h"
10 | #import
11 | #import "NSObject+Detector.h"
12 |
13 | @interface WTLeaksDetector()
14 |
15 | @property (nonatomic, strong) NSTimer* pingTimer;
16 |
17 | @end
18 |
19 | @implementation WTLeaksDetector
20 |
21 | + (instancetype)sharedInstance {
22 | static WTLeaksDetector* instance = nil;
23 |
24 | static dispatch_once_t onceToken;
25 | dispatch_once(&onceToken, ^{
26 | instance = [WTLeaksDetector new];
27 | });
28 |
29 | return instance;
30 | }
31 |
32 | -(void)startDetector {
33 |
34 | [UINavigationController prepareForDetector];
35 | [UIViewController prepareForDetector];
36 |
37 | [self startPingTimer];
38 |
39 | [[NSNotificationCenter defaultCenter] removeObserver:self name:Notif_WTDetector_Pong object:nil];
40 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(detectPong:) name:Notif_WTDetector_Pong object:nil];
41 | }
42 |
43 | - (void)startPingTimer
44 | {
45 | if ([NSThread isMainThread] == false) {
46 | dispatch_async(dispatch_get_main_queue(), ^{
47 | [self startPingTimer];
48 | return ;
49 | });
50 | }
51 |
52 | if (self.pingTimer) {
53 | return;
54 | }
55 |
56 | self.pingTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
57 | target:self
58 | selector:@selector(sendPing)
59 | userInfo:nil
60 | repeats:true];
61 |
62 | [[NSRunLoop currentRunLoop] addTimer:self.pingTimer forMode:NSRunLoopCommonModes];
63 | }
64 |
65 | - (void)sendPing {
66 | [[NSNotificationCenter defaultCenter] postNotificationName:Notif_WTDetector_Ping object:nil];
67 | }
68 |
69 | - (void)detectPong:(NSNotification*)notif {
70 | NSObject* leakedObject = notif.object;
71 |
72 | if ([leakedObject isKindOfClass:[UIViewController class]]) {
73 | NSLog(@"\n\nDetect Possible Controller Leak: %@ \n\n", [leakedObject class]);
74 | }else{
75 | NSLog(@"\n\nDetect Possible Leak: %@ \n\n", [leakedObject class]);
76 | }
77 | }
78 |
79 | @end
80 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/WTObjectProxy.h:
--------------------------------------------------------------------------------
1 | //
2 | // WTObjectProxy.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface WTObjectProxy : NSObject
12 |
13 | -(void)prepareProxy:(NSObject *)target;
14 |
15 | @property (nonatomic, weak) NSObject *weakTarget;
16 | @property (nonatomic, weak) NSObject *weakResponder;// uiview responder
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/cpapm/APM/Leaks/WTObjectProxy.m:
--------------------------------------------------------------------------------
1 | //
2 | // WTObjectProxy.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/11.
6 | // Copyright © 2018年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "WTObjectProxy.h"
10 | #import "WTLeaksDetector.h"
11 | #import "NSObject+Detector.h"
12 |
13 | #define kLeakCheckMaxFailCount 5
14 |
15 | @interface WTObjectProxy()
16 |
17 | @property (nonatomic, assign) BOOL markLeaks;
18 | @property (nonatomic, assign) NSInteger checkLeaksCount;
19 |
20 | @end
21 |
22 | @implementation WTObjectProxy
23 |
24 | -(void)prepareProxy:(NSObject *)target {
25 |
26 | self.weakTarget = target;
27 |
28 | [[NSNotificationCenter defaultCenter] removeObserver:self name:Notif_WTDetector_Ping object:nil];
29 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(detectPing) name:Notif_WTDetector_Ping object:nil];
30 | }
31 |
32 | -(void)detectPing {
33 | if (!self.weakTarget) {
34 | return;
35 | }
36 | if (_markLeaks) {
37 | return;
38 | }
39 |
40 | BOOL alive = [self.weakTarget isAlive];
41 | if (alive == false) {
42 | _checkLeaksCount += 1;
43 | }
44 |
45 | if (self.checkLeaksCount >= kLeakCheckMaxFailCount) {
46 | _markLeaks = true;
47 | NSLog(@"*** %@ is still alive *** \n",self.weakTarget);
48 | [[NSNotificationCenter defaultCenter] postNotificationName:Notif_WTDetector_Pong object:self.weakTarget];
49 | }
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/CFNet.h:
--------------------------------------------------------------------------------
1 | //
2 | // CFNet.h
3 | // WellTangAPM
4 | //
5 | // Created by yangyouyong on 2018/1/12.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CFNet : NSObject
12 |
13 | @property (nonatomic, strong) NSMutableDictionary *responseMap;
14 | @property (nonatomic, strong) NSMutableDictionary *responseDataMap;
15 |
16 | // hook cfnetwork
17 | +(void)install;
18 |
19 | -(void)testCFGetClient;
20 | -(void)testCFGetClient2;
21 |
22 | -(void)testCFGetClientCompletion:(void(^)(NSData *))completionBlock;
23 |
24 | -(void)testCFGetClientCompletion:(void(^)(NSData *))completionBlock;
25 | -(void)testCFGetClient2Completion:(void(^)(NSData *))completionBlock;
26 |
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/CFNet.m:
--------------------------------------------------------------------------------
1 | //
2 | // CFNet.m
3 | // WellTangAPM
4 | //
5 | // Created by yangyouyong on 2018/1/12.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #import "CFNet.h"
10 | #import "Hook_CFNetwork.h"
11 | #import "fishhook.h"
12 |
13 | @implementation CFNet
14 |
15 | +(void)install {
16 |
17 | struct rebinding _rebinding = { "CFReadStreamSetClient", wt_CFReadStreamSetClient, (void *)&original_CFReadStreamSetClient};
18 | struct rebinding _request_binding = { "CFReadStreamCreateForHTTPRequest", wt_CFReadStreamCreateForHTTPRequest, (void *)&original_CFReadStreamCreateForHTTPRequest};
19 | struct rebinding _stream_open_binding = { "CFReadStreamOpen", wt_CFReadStreamOpen, (void *)&original_CFReadStreamOpen};
20 | struct rebinding _stream_close_binding = { "CFReadStreamClose", wt_CFReadStreamClose, (void *)&original_CFReadStreamClose};
21 | struct rebinding _stream_setproperty_binding = { "CFReadStreamSetProperty", wt_CFReadStreamSetProperty, (void *)&original_CFReadStreamSetProperty};
22 | rebind_symbols(
23 | (struct rebinding[5]){
24 | _rebinding,
25 | _request_binding,
26 | _stream_open_binding,
27 | _stream_close_binding,
28 | _stream_setproperty_binding
29 | }, 5);
30 | }
31 |
32 | // sync function
33 | -(void)CFTest {
34 |
35 | CFStringRef headerFieldName = CFSTR("this is a header");
36 | CFStringRef headerFieldValue = CFSTR("value");
37 | //创建url
38 | CFStringRef url1 = CFSTR("http://c.hiphotos.baidu.com/image/w%3D310/sign=b8f7695888d4b31cf03c92bab7d6276f/4e4a20a4462309f76248df09710e0cf3d7cad682.jpg");
39 | CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, url1, NULL);
40 | //设置请求方式
41 | CFStringRef requestMethod = CFSTR("GET");
42 | //创建请求
43 | CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault,requestMethod, myURL, kCFHTTPVersion1_1);
44 | //设置头信息
45 | CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
46 | //创建CFReadStreamRef对象来序列化并发送CFHTTP请求,注意CFReadStreamCreateForHTTPRequest在iOS 9.0开始已经有DEPRECATED警告,
47 | #pragma clang diagnostic push
48 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
49 | CFReadStreamRef myReadStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myRequest);
50 | #pragma clang diagnostic pop
51 | //打开读取流
52 | CFReadStreamOpen(myReadStream);
53 | //存放响应数据
54 | NSMutableData *responseBytes = [NSMutableData data];
55 | CFIndex numBytesRead = 0;
56 | //从流中读取数据,读完为止,其中CFReadStreamRead会阻塞代码
57 | do {
58 | UInt8 buf[1024];
59 | numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));
60 |
61 | if (numBytesRead > 0) {
62 | [responseBytes appendBytes:buf length:numBytesRead];
63 | }
64 | } while (numBytesRead > 0);
65 | //读取响应头信息
66 | #pragma clang diagnostic push
67 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
68 | CFHTTPMessageRef myResponse = (CFHTTPMessageRef) CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
69 | #pragma clang diagnostic pop
70 | //读取statusCode
71 | CFIndex statusCode = CFHTTPMessageGetResponseStatusCode(myResponse);
72 | //打印数据
73 | if(statusCode == 200) {
74 | //NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseBytes options:NSJSONReadingMutableLeaves error:nil];
75 | NSLog(@"%@", responseBytes);
76 | }
77 | }
78 |
79 | -(void)testCFGetClient {
80 | CFStringRef urlStr = CFSTR("http://c.hiphotos.baidu.com/image/w%3D310/sign=b8f7695888d4b31cf03c92bab7d6276f/4e4a20a4462309f76248df09710e0cf3d7cad682.jpg");
81 | [self testClientGet: urlStr completion:^(NSData * responseData) {
82 | NSLog(@"first_response");
83 | // weakSelf.responseImageView.image = [UIImage imageWithData:responseData];
84 | }];
85 | }
86 | -(void)testCFGetClient2 {
87 |
88 | CFStringRef urlStr = CFSTR("http://e.hiphotos.baidu.com/image/pic/item/500fd9f9d72a6059099ccd5a2334349b023bbae5.jpg");
89 | [self testClientGet: urlStr completion:^(NSData *responseData) {
90 | NSLog(@"second_response");
91 | // weakSelf.secondResponseImageView.image = [UIImage imageWithData:responseData];;
92 | }];
93 | }
94 |
95 | -(void)testCFGetClientCompletion:(void(^)(NSData *))completionBlock {
96 | CFStringRef urlStr = CFSTR("http://c.hiphotos.baidu.com/image/w%3D310/sign=b8f7695888d4b31cf03c92bab7d6276f/4e4a20a4462309f76248df09710e0cf3d7cad682.jpg");
97 | [self testClientGet: urlStr completion:^(NSData * responseData) {;
98 | if (completionBlock) {
99 | completionBlock(responseData);
100 | }
101 | }];
102 | }
103 | -(void)testCFGetClient2Completion:(void(^)(NSData *))completionBlock {
104 | CFStringRef urlStr = CFSTR("http://e.hiphotos.baidu.com/image/pic/item/500fd9f9d72a6059099ccd5a2334349b023bbae5.jpg");
105 | [self testClientGet: urlStr completion:^(NSData *responseData) {
106 | if (completionBlock) {
107 | completionBlock(responseData);
108 | }
109 | }];
110 | }
111 |
112 | -(void)testClientGet:(CFStringRef)urlStr completion:(void(^)(NSData *))completionBlock {
113 | // CFStringRef urlStr = CFSTR("http://c.hiphotos.baidu.com/image/w%3D310/sign=b8f7695888d4b31cf03c92bab7d6276f/4e4a20a4462309f76248df09710e0cf3d7cad682.jpg");
114 |
115 | //GET请求
116 | CFStringRef method = CFSTR("GET");
117 |
118 | //构造URL
119 | CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL);
120 |
121 | //http请求
122 | CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, method, url, kCFHTTPVersion1_1);
123 |
124 | //创建一个读取流 读取网络数据
125 | CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
126 |
127 | NSString *uniqueValue = [NSString stringWithFormat:@"%.2f_%@",[[NSDate date] timeIntervalSince1970], (__bridge NSString *)urlStr];
128 | if (!self.responseMap) {
129 | self.responseMap = @{}.mutableCopy;
130 | }
131 | if (self.responseMap) {
132 | self.responseMap[uniqueValue] = completionBlock;
133 | }
134 | CFReadStreamSetProperty((CFReadStreamRef)readStream, CFSTR("CFStreamID"), (__bridge CFTypeRef)(uniqueValue));
135 |
136 | // uniqueValue add to call back map
137 | CFStringRef requestHeader = CFSTR("CFStreamID");
138 | CFStringRef requestHeaderValue = (__bridge CFStringRef)uniqueValue;
139 | CFHTTPMessageSetHeaderFieldValue(request, requestHeader, requestHeaderValue);
140 | NSMutableDictionary *proxyToUse = @{@"CFStreamID": uniqueValue};
141 | CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, (__bridge CFTypeRef)(proxyToUse));
142 | CFStreamClientContext ctxt = {0, (__bridge void *)(self), NULL, NULL, NULL};
143 |
144 |
145 | //监听回调事件
146 | // kCFStreamEventNone,(没有事件发生)
147 | //
148 | // kCFStreamEventOpenCompleted,(流被成功打开)
149 | //
150 | // kCFStreamEventHasBytesAvailable,(有数据可以读取)
151 | //
152 | // kCFStreamEventCanAcceptBytes,(流可以接受写入数据(用于写入流))
153 | //
154 | // kCFStreamEventErrorOccurred,(在流上有错误发生)
155 | //
156 | // kCFStreamEventEndEncountered ,(到达了流的结束位置)
157 | CFOptionFlags event = kCFStreamEventHasBytesAvailable|kCFStreamEventEndEncountered;
158 |
159 | //设值回调函数myCallBack
160 |
161 | CFReadStreamSetClient(readStream,event,CFReadStreamCallBack,&ctxt);
162 |
163 | CFReadStreamScheduleWithRunLoop(readStream,CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
164 |
165 | CFReadStreamOpen(readStream);
166 |
167 | }
168 |
169 | void CFReadStreamCallBack (CFReadStreamRef stream,CFStreamEventType type,void *clientCallBackInfo){
170 |
171 |
172 | NSDictionary *proxyInfo = CFBridgingRelease(CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPProxy));
173 | CFNet *client = (__bridge CFNet *)clientCallBackInfo;
174 |
175 | CFTypeRef uniqueValue = (__bridge CFTypeRef)(proxyInfo[@"CFStreamID"]);
176 |
177 | if (!client.responseDataMap) {
178 | client.responseDataMap = @{}.mutableCopy;
179 | }
180 | if (client.responseDataMap && [(__bridge NSString *)uniqueValue length] > 0) {
181 | if (client.responseDataMap[(__bridge NSString *)(uniqueValue)] == nil) {
182 | client.responseDataMap[(__bridge NSString *)(uniqueValue)] = [NSMutableData data];
183 | }
184 | }
185 |
186 | if(type == kCFStreamEventHasBytesAvailable){
187 | UInt8 buff[255];
188 | long length = CFReadStreamRead(stream, buff, 255);
189 | NSMutableData *imageData = client.responseDataMap[(__bridge NSString *)(uniqueValue)];
190 | if(!imageData){
191 | imageData = [[NSMutableData alloc] init];
192 | }
193 | [imageData appendBytes:buff length:length];
194 |
195 | client.responseDataMap[(__bridge NSString *)(uniqueValue)] = imageData;
196 | }else if(type == kCFStreamEventEndEncountered){
197 |
198 | void(^completionBlock)(NSData *) = client.responseMap[(__bridge NSString *)(uniqueValue)];
199 | if (completionBlock) {
200 | NSData *resData = client.responseDataMap[(__bridge NSString *)(uniqueValue)];
201 | // 9631bytes test:196403
202 | // 19356bytes test:746106
203 | completionBlock(resData);
204 | }
205 |
206 | CFReadStreamClose(stream);
207 | CFReadStreamUnscheduleFromRunLoop(stream,CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
208 | }
209 | }
210 |
211 | void postmyCallBack (CFReadStreamRef stream,CFStreamEventType type,void *clientCallBackInfo){
212 |
213 | NSLog(@"myCallBack is %@",clientCallBackInfo);
214 |
215 | static NSMutableData* imageData = nil;
216 |
217 | if(type == kCFStreamEventHasBytesAvailable){
218 | UInt8 buff[255];
219 | long length = CFReadStreamRead(stream, buff, 255);
220 | NSLog(@"length is %ld",length);
221 | if(!imageData){
222 | imageData = [[NSMutableData alloc] init];
223 | }
224 | [imageData appendBytes:buff length:length];
225 |
226 |
227 | }else if(type == kCFStreamEventEndEncountered){
228 |
229 | NSString* resString = [[NSString alloc] initWithData:imageData encoding:NSUTF8StringEncoding];
230 | NSLog(@"resString is %@",resString);
231 | CFReadStreamClose(stream);
232 | CFReadStreamUnscheduleFromRunLoop(stream,CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
233 | }
234 | }
235 | - (IBAction)testCFPostClient:(id)sender {
236 | [self testClientPOST];
237 | }
238 |
239 | -(void)testClientPOST {
240 | CFStringRef urlStr = CFSTR("https://upload.api.weibo.com/2/statuses/upload.json");
241 |
242 | //GET请求
243 | CFStringRef method= CFSTR("POST");
244 |
245 | //构造URL
246 | CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL);
247 |
248 | //http请求
249 | CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, method, url, kCFHTTPVersion1_1);
250 |
251 | NSString *boundary = [NSString stringWithFormat:@"---------------------------14737809dasdasda2746641449"];
252 | NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
253 |
254 | //OC的字符串要做C框架中使用需要__bridge桥接
255 | CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Content-Type"), (__bridge CFStringRef)(contentType));
256 |
257 | NSData *bodyData = [self getRequestData];
258 | CFHTTPMessageSetBody(request, (__bridge CFDataRef)(bodyData));
259 |
260 |
261 | CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
262 |
263 | //设置流的context这里将self传入,用于以后的回调
264 | CFStreamClientContext ctxt = {0, (__bridge void *)(self), NULL, NULL, NULL};
265 |
266 | CFOptionFlags event = kCFStreamEventHasBytesAvailable|kCFStreamEventEndEncountered;
267 |
268 | CFReadStreamSetClient(readStream,event,postmyCallBack,&ctxt);
269 |
270 | CFReadStreamScheduleWithRunLoop(readStream,CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
271 |
272 | CFReadStreamOpen(readStream);
273 | }
274 |
275 | // TODO: finish
276 | - (NSData *)getRequestData{
277 |
278 |
279 | NSData *imageData = nil;
280 |
281 |
282 | //分隔符,注意要与上面请求头中的一致
283 | NSString *boundary = [NSString stringWithFormat:@"---------------------------14737809dasdasda2746641449"];
284 |
285 |
286 | //定义可变Data;
287 | NSMutableData *body = [NSMutableData data];
288 |
289 | //分隔符
290 | [body appendData:[[NSString stringWithFormat:@"\r\n\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
291 |
292 | //需要发送的文字内容
293 | [body appendData:[@"Content-Disposition: form-data; name=\"status\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
294 | [body appendData:[@"需要发送的文字内容\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
295 |
296 | //分隔符
297 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
298 |
299 | //需要发送的图片内容
300 | [body appendData:[@"Content-Disposition: form-data; name=\"pic\"; filename=\"cat.png\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
301 | [body appendData:[@"Content-Type: image/png\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
302 | [body appendData:[NSData dataWithData:imageData]];
303 |
304 | //分割符
305 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
306 |
307 | //access_token 向新浪微博发送内容,需要OAuth认证,这里必须带上access_token
308 | [body appendData:[@"Content-Disposition: form-data; name=\"access_token\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
309 |
310 | [body appendData:[@"2.00svaeojkrewe901dPLialB" dataUsingEncoding:NSUTF8StringEncoding]];
311 |
312 | //结尾注意这里的分割符和前面不一样,--%@--后面多了两条--,如果少了会发送不成功哦
313 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
314 |
315 | return body;
316 | }
317 |
318 | @end
319 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/CFNetProxy.h:
--------------------------------------------------------------------------------
1 | //
2 | // CFNetProxy.h
3 | // WellTangAPM
4 | //
5 | // Created by yangyouyong on 2018/1/15.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "CFNetProxyModel.h"
11 |
12 | @interface CFNetProxy : NSObject
13 |
14 | @property (nonatomic, strong) NSMutableDictionary *requestMap;
15 | +(CFNetProxy *)sharedInstance;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/CFNetProxy.m:
--------------------------------------------------------------------------------
1 | //
2 | // CFNetProxy.m
3 | // WellTangAPM
4 | //
5 | // Created by yangyouyong on 2018/1/15.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #import "CFNetProxy.h"
10 | #import "Hook_CFNetwork.h"
11 |
12 | @implementation CFNetProxy
13 |
14 | + (CFNetProxy *)sharedInstance
15 | {
16 | static CFNetProxy *instance = nil;
17 | static dispatch_once_t onceToken;
18 | dispatch_once(&onceToken, ^{
19 | instance = [[CFNetProxy alloc] init];
20 | instance.requestMap = @{}.mutableCopy;
21 | });
22 | return instance;
23 | }
24 | @end
25 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/CFNetProxyModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // CFNetProxyModel.h
3 | // WellTangAPM
4 | //
5 | // Created by yangyouyong on 2018/1/15.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | /**
13 | proxy model remember cf hook call back and request send argv
14 | */
15 | @interface CFNetProxyModel : NSObject
16 |
17 | @property (nonatomic, copy) NSString *requestId; // mark request
18 |
19 | @property (nonatomic, strong) NSValue *callbackPointer; // call back method pointer
20 | @property (nonatomic, strong) NSValue *contextPointer; // context pointer
21 |
22 | @property (nonatomic, strong) NSMutableDictionary *readStreamProperty;
23 | @property (nonatomic, strong) NSMutableDictionary *requestHeaderFields;
24 | @property (nonatomic, strong) NSMutableDictionary *responseHeaderFields;
25 | @property (nonatomic, strong) NSMutableData *responseData;
26 | @property (nonatomic, strong) NSMutableData *bufferData;
27 |
28 | +(NSString *)createReuestIdForRequest:(CFHTTPMessageRef)request;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/CFNetProxyModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // CFNetProxyModel.m
3 | // WellTangAPM
4 | //
5 | // Created by yangyouyong on 2018/1/15.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #import "CFNetProxyModel.h"
10 |
11 | @implementation CFNetProxyModel
12 |
13 | +(NSString *)createReuestIdForRequest:(CFHTTPMessageRef)request {
14 | NSURL *url = (__bridge NSURL *)CFHTTPMessageCopyRequestURL(request);
15 | NSString *method = (__bridge NSString *)CFHTTPMessageCopyRequestMethod(request);
16 | NSTimeInterval nowTime = [[NSDate date] timeIntervalSince1970];
17 | return [NSString stringWithFormat:@"%@_%@_%.2f",url.absoluteString, method, nowTime];
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/Hook_CFNetwork.h:
--------------------------------------------------------------------------------
1 | //
2 | // Hook_CFNetwork.h
3 | // WellTangAPM
4 | //
5 | // Created by yangyouyong on 2018/1/12.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "CFNetProxy.h"
12 | #import "CFNet.h"
13 |
14 | #define CFRequest_KEY @"hook_requestId"
15 |
16 | // TODO: proxystream receive data and send data to target stream;
17 | static void hooked_proxyCallBack(CFReadStreamRef stream,CFStreamEventType type,void *clientCallBackInfo);
18 | void hooked_proxyCallBack(CFReadStreamRef stream,CFStreamEventType type,void *clientCallBackInfo){
19 |
20 | NSDictionary *proxyInfo = CFBridgingRelease(CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPProxy));
21 | NSString *requestId = proxyInfo[CFRequest_KEY];
22 | NSMutableDictionary *proxyCallBackMap = [CFNetProxy sharedInstance].requestMap;
23 |
24 | CFReadStreamClientCallBack original_callback = NULL;
25 | if (clientCallBackInfo != NULL) {
26 | CFNetProxyModel *proxy = proxyCallBackMap[requestId];
27 | if (proxy) {
28 | original_callback = [proxy.callbackPointer pointerValue];
29 | }else{
30 | NSLog(@"missed_data");
31 | }
32 | }
33 |
34 | CFReadStreamRef readStream = stream;
35 |
36 | if(type == kCFStreamEventHasBytesAvailable){
37 |
38 | CFNetProxyModel *proxy = proxyCallBackMap[requestId];
39 | if (proxy) {
40 | // proxy receive data
41 | /**
42 | UInt8 buff[255];
43 | long length = CFReadStreamRead(stream, buff, 255);
44 | NSMutableData *mutiData = proxy.bufferData;
45 | if(!mutiData){
46 | mutiData = [[NSMutableData alloc] init];
47 | }
48 | [mutiData appendBytes:buff length:length];
49 |
50 | proxy.bufferData = mutiData;
51 | */
52 | }
53 |
54 | }else if(type == kCFStreamEventEndEncountered){
55 |
56 | // end data
57 | CFNetProxyModel *proxy = proxyCallBackMap[requestId];
58 | if (proxy) {
59 | proxy.responseData = proxy.bufferData;
60 | }
61 | NSLog(@"proxy complete");
62 | }
63 |
64 | if (original_callback != NULL) {
65 | original_callback(readStream, type, clientCallBackInfo);
66 | }
67 | }
68 |
69 | static Boolean (*original_CFReadStreamSetClient)(CFReadStreamRef, CFOptionFlags, CFReadStreamClientCallBack, CFStreamClientContext *);
70 |
71 | static Boolean wt_CFReadStreamSetClient(CFReadStreamRef stream, CFOptionFlags streamEvents, CFReadStreamClientCallBack clientCB, CFStreamClientContext *clientContext);
72 |
73 | Boolean wt_CFReadStreamSetClient(CFReadStreamRef stream, CFOptionFlags streamEvents, CFReadStreamClientCallBack clientCB, CFStreamClientContext *clientContext) {
74 |
75 | NSDictionary *proxyInfo = CFBridgingRelease(CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPProxy));
76 | NSString *requestId = proxyInfo[CFRequest_KEY];
77 |
78 | NSMutableDictionary *proxyCallBackMap = [CFNetProxy sharedInstance].requestMap;
79 | if (clientContext != NULL && clientContext->info != NULL) {
80 | NSValue *objectKey = [NSValue valueWithPointer:clientContext->info];
81 | CFNetProxyModel *proxy = proxyCallBackMap[requestId];
82 | if (proxy && proxy.callbackPointer == nil) {
83 |
84 | proxy.callbackPointer = [NSValue valueWithPointer:clientCB];
85 | return original_CFReadStreamSetClient(stream, streamEvents, hooked_proxyCallBack, clientContext);
86 | }
87 | }
88 |
89 | return original_CFReadStreamSetClient(stream, streamEvents, clientCB, clientContext);
90 | }
91 |
92 | static CFReadStreamRef (*original_CFReadStreamCreateForHTTPRequest)(CFAllocatorRef, CFHTTPMessageRef);
93 |
94 | static CFReadStreamRef
95 | wt_CFReadStreamCreateForHTTPRequest(CFAllocatorRef __nullable alloc, CFHTTPMessageRef request);
96 | CFReadStreamRef wt_CFReadStreamCreateForHTTPRequest(CFAllocatorRef __nullable alloc, CFHTTPMessageRef request) {
97 |
98 | NSURL *url = (__bridge NSURL *)CFHTTPMessageCopyRequestURL(request);
99 | NSString *method = (__bridge NSString *)CFHTTPMessageCopyRequestMethod(request);
100 | NSString *requestId = [CFNetProxyModel createReuestIdForRequest:request];
101 | CFReadStreamRef readStream = original_CFReadStreamCreateForHTTPRequest(alloc, request);
102 |
103 | CFReadStreamSetProperty(readStream, CFSTR("StreamID"), (__bridge CFTypeRef)requestId);
104 |
105 | // mark request
106 | NSDictionary *proxyInfo = CFBridgingRelease(CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPProxy));
107 | NSMutableDictionary *userInfo = [proxyInfo mutableCopy];
108 | if (userInfo == nil) {
109 | userInfo = @{}.mutableCopy;
110 | }
111 | userInfo[CFRequest_KEY] = requestId;
112 | CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, (__bridge CFTypeRef)(userInfo));
113 |
114 | NSMutableDictionary *proxyCallBackMap = [CFNetProxy sharedInstance].requestMap;
115 | if (requestId.length > 0) {
116 | if (!proxyCallBackMap[requestId]) {
117 | CFNetProxyModel *model = [CFNetProxyModel new];
118 | model.requestId = requestId;
119 | proxyCallBackMap[requestId] = model;
120 | }
121 | }
122 | return readStream;
123 | }
124 |
125 | // TODO: mark request status
126 | static Boolean (*original_CFReadStreamOpen)(CFReadStreamRef);
127 | static Boolean wt_CFReadStreamOpen(CFReadStreamRef stream);
128 | Boolean wt_CFReadStreamOpen(CFReadStreamRef stream) {
129 |
130 | return original_CFReadStreamOpen(stream);
131 | }
132 |
133 | // TODO: mark request status
134 | static Boolean (*original_CFReadStreamClose)(CFReadStreamRef);
135 | static Boolean wt_CFReadStreamClose(CFReadStreamRef stream);
136 | Boolean wt_CFReadStreamClose(CFReadStreamRef stream) {
137 | NSDictionary *proxyInfo = CFBridgingRelease(CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPProxy));
138 | return original_CFReadStreamClose(stream);
139 | }
140 |
141 | static CFTypeRef (*original_CFReadStreamSetProperty)(CFReadStreamRef, CFStreamPropertyKey, CFTypeRef);
142 | static Boolean wt_CFReadStreamSetProperty(CFReadStreamRef stream, CFStreamPropertyKey propertyName, CFTypeRef propertyValue);
143 | Boolean wt_CFReadStreamSetProperty(CFReadStreamRef stream, CFStreamPropertyKey propertyName, CFTypeRef propertyValue) {
144 |
145 | if (propertyName == kCFStreamPropertyHTTPProxy) {
146 | NSDictionary *proxyInfo = CFBridgingRelease(CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPProxy));
147 | NSMutableDictionary *userInfo = [proxyInfo mutableCopy];
148 | if (userInfo == nil) {
149 | return original_CFReadStreamSetProperty(stream,propertyName, propertyValue);
150 | }
151 | id va = (__bridge id)propertyValue;
152 | if ([va isKindOfClass:[NSDictionary class]]) {
153 | NSDictionary *infoDict = va;
154 | for (NSString *key in [infoDict allKeys]) {
155 | id value = infoDict[key];
156 | userInfo[key] = value;
157 | }
158 | }
159 | return original_CFReadStreamSetProperty(stream,propertyName, (__bridge CFTypeRef)userInfo);
160 | }
161 |
162 | return original_CFReadStreamSetProperty(stream,propertyName, propertyValue);
163 | }
164 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/Hook_CFNetwork.m:
--------------------------------------------------------------------------------
1 | //
2 | // Hook_CFNetwork.m
3 | // WellTangAPM
4 | //
5 | // Created by yangyouyong on 2018/1/12.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #import "Hook_CFNetwork.h"
10 |
11 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/NetAnt.h:
--------------------------------------------------------------------------------
1 | //
2 | // NetAnt.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @protocol NetAntDelegate
12 |
13 | -(void)netAntDidCatchRequest:(NSURLRequest *)request response:(NSURLResponse *)response data:(NSData *)data;
14 |
15 | @end
16 |
17 | @interface NetAnt : NSObject
18 |
19 | @property (nonatomic, assign) id delegate;
20 |
21 | +(BOOL)isWatching;
22 |
23 | +(void)addObserver:(id)delegate;
24 |
25 | +(void)removeObserver:(id)delegate;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/NetAnt.m:
--------------------------------------------------------------------------------
1 | //
2 | // NetAnt.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "NetAnt.h"
10 | #import "NetProtocol.h"
11 | #import "NetAntURLSessionConfiguration.h"
12 |
13 | @implementation NetAnt
14 |
15 | +(BOOL)isWatching {
16 | return [NetProtocol delegates].count > 0;
17 | }
18 |
19 | +(void)addObserver:(id)delegate {
20 | if ([NetProtocol delegates].count <= 0) {
21 | [NetProtocol open];
22 | [NetAntURLSessionConfiguration open];
23 | }
24 | [NetProtocol addDelegate:delegate];
25 | }
26 |
27 | +(void)removeObserver:(id)delegate {
28 | [NetProtocol removeDelegate:delegate];
29 | if ([NetProtocol delegates].count <= 0) {
30 | [NetProtocol close];
31 | [NetAntURLSessionConfiguration close];
32 | }
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/NetAntURLSessionConfiguration.h:
--------------------------------------------------------------------------------
1 | //
2 | // NetAntURLSessionConfiguration.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NetAntURLSessionConfiguration : NSObject
12 |
13 | @property (nonatomic,assign) BOOL isSwizzle;
14 | + (NetAntURLSessionConfiguration *)defaultConfiguration;
15 |
16 | +(void)open;
17 | +(void)close;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/NetAntURLSessionConfiguration.m:
--------------------------------------------------------------------------------
1 | //
2 | // NetAntURLSessionConfiguration.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "NetAntURLSessionConfiguration.h"
10 | #import
11 | #import "NetProtocol.h"
12 |
13 | @implementation NetAntURLSessionConfiguration
14 |
15 | + (NetAntURLSessionConfiguration *)defaultConfiguration {
16 |
17 | static NetAntURLSessionConfiguration *staticConfiguration;
18 | static dispatch_once_t onceToken;
19 | dispatch_once(&onceToken, ^{
20 | staticConfiguration=[[NetAntURLSessionConfiguration alloc] init];
21 | });
22 | return staticConfiguration;
23 | }
24 |
25 | +(void)open {
26 | NetAntURLSessionConfiguration *defaultInstance = [NetAntURLSessionConfiguration defaultConfiguration];
27 | if (![defaultInstance isSwizzle]) {
28 | [defaultInstance load];
29 | }
30 | }
31 |
32 | +(void)close {
33 | NetAntURLSessionConfiguration *defaultInstance = [NetAntURLSessionConfiguration defaultConfiguration];
34 | if ([defaultInstance isSwizzle]) {
35 | [defaultInstance unload];
36 | }
37 | }
38 |
39 | - (instancetype)init {
40 | self = [super init];
41 | if (self) {
42 | self.isSwizzle=NO;
43 | }
44 | return self;
45 | }
46 |
47 | - (void)load {
48 |
49 | self.isSwizzle=YES;
50 | Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");
51 | [self swizzleSelector:@selector(protocolClasses) fromClass:cls toClass:[self class]];
52 |
53 | }
54 |
55 | - (void)unload {
56 |
57 | self.isSwizzle=NO;
58 | Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");
59 | [self swizzleSelector:@selector(protocolClasses) fromClass:cls toClass:[self class]];
60 |
61 | }
62 |
63 | - (void)swizzleSelector:(SEL)selector fromClass:(Class)original toClass:(Class)stub {
64 |
65 | Method originalMethod = class_getInstanceMethod(original, selector);
66 | Method stubMethod = class_getInstanceMethod(stub, selector);
67 | if (!originalMethod || !stubMethod) {
68 | [NSException raise:NSInternalInconsistencyException format:@"Couldn't load NEURLSessionConfiguration."];
69 | }
70 | method_exchangeImplementations(originalMethod, stubMethod);
71 | }
72 |
73 | //如果需要导入其他的自定义NSURLProtocol请在这里增加,当然在使用NSURLSessionConfiguration时增加也可以
74 | - (NSArray *)protocolClasses {
75 |
76 | return @[[NetProtocol class]];
77 | }
78 |
79 | @end
80 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/NetProtocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // NetProtocol.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "NetAnt.h"
11 |
12 | @interface NetProtocol : NSURLProtocol
13 |
14 | +(void)open;
15 | +(void)close;
16 |
17 | +(void)addDelegate:(id)delegate;
18 | +(void)removeDelegate:(id)delegate;
19 |
20 | +(NSArray *)delegates;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/NetProtocol.m:
--------------------------------------------------------------------------------
1 | //
2 | // NetProtocol.m
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2017/12/28.
6 | // Copyright © 2017年 cpbee. All rights reserved.
7 | //
8 |
9 | #import "NetProtocol.h"
10 |
11 | @interface NetProtocol()
12 |
13 | @property (nonatomic, strong) NSURLConnection *connection;
14 | @property (nonatomic, strong) NSURLRequest *ant_request;
15 | @property (nonatomic, strong) NSURLResponse *ant_response;
16 | @property (nonatomic, strong) NSMutableData *ant_data;
17 |
18 | @end
19 |
20 | static NSMutableArray *delegates = nil;
21 | static NSString *greenCard = @"greenCard";
22 |
23 | @implementation NetProtocol
24 |
25 | +(void)open {
26 | [NSURLProtocol registerClass:[self class]];
27 | }
28 |
29 | +(void)close {
30 | [NSURLProtocol unregisterClass:[self class]];
31 | }
32 |
33 | +(void)addDelegate:(id)delegate {
34 | if (!delegates) {
35 | delegates = @[].mutableCopy;
36 | }
37 | BOOL contains = [delegates containsObject:delegate];
38 | if (!contains) {
39 | [delegates addObject:delegate];
40 | }
41 | }
42 |
43 | +(void)removeDelegate:(id)delegate {
44 | [delegates removeObject:delegate];
45 | }
46 |
47 | +(NSArray *)delegates {
48 | return delegates;
49 | }
50 |
51 | #pragma mark -- override
52 | +(BOOL)canInitWithRequest:(NSURLRequest *)request {
53 |
54 | if (![request.URL.scheme isEqualToString:@"http"] &&
55 | ![request.URL.scheme isEqualToString:@"https"]) {
56 | return NO;
57 | }
58 |
59 | if ([NSURLProtocol propertyForKey:greenCard inRequest:request] ) {
60 | return NO;
61 | }
62 | return YES;
63 | }
64 |
65 | + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
66 |
67 | NSMutableURLRequest *mutableReqeust = [request mutableCopy];
68 | [NSURLProtocol setProperty:@YES
69 | forKey:greenCard
70 | inRequest:mutableReqeust];
71 | return [mutableReqeust copy];
72 | }
73 |
74 | -(void)startLoading {
75 |
76 | NSURLRequest *request = [NetProtocol canonicalRequestForRequest:self.request];
77 |
78 | #pragma clang diagnostic push
79 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
80 | self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
81 | #pragma clang diagnostic pop
82 |
83 | self.ant_request = self.request;
84 | }
85 |
86 | -(void)stopLoading {
87 | [self.connection cancel];
88 | for (id delegate in delegates) {
89 | [delegate netAntDidCatchRequest:self.ant_request response:self.ant_response data:self.ant_data];
90 | }
91 | }
92 |
93 | #pragma mark - connection delegate & data
94 |
95 | -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
96 | [self.client URLProtocol:self didFailWithError:error];
97 | }
98 |
99 | -(BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection {
100 | return true;
101 | }
102 |
103 | -(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
104 | [self.client URLProtocol:self didReceiveAuthenticationChallenge:challenge];
105 | }
106 |
107 | -(void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
108 | [self.client URLProtocol:self didCancelAuthenticationChallenge:challenge];
109 | }
110 |
111 | #pragma mark - data
112 |
113 | -(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response {
114 | if (response != nil) {
115 | self.ant_response = response;
116 | [self.client URLProtocol:self wasRedirectedToRequest:request redirectResponse:response];
117 | }
118 | return request;
119 | }
120 |
121 | -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
122 | [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
123 | self.ant_response = response;
124 | }
125 |
126 | -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
127 | [self.client URLProtocol:self didLoadData:data];
128 | if (self.ant_data == nil) {
129 | self.ant_data = [data mutableCopy];
130 | }else{
131 | [self.ant_data appendData:data];
132 | }
133 | }
134 |
135 | -(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
136 | return cachedResponse;
137 | }
138 |
139 | -(void)connectionDidFinishLoading:(NSURLConnection *)connection {
140 | [self.client URLProtocolDidFinishLoading:self];
141 | }
142 |
143 | @end
144 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/SocketBasedRequest/CHttpRequest.c:
--------------------------------------------------------------------------------
1 | //
2 | // CHttpRequest.c
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/29.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #include "CHttpRequest.h"
10 |
11 | //int main(int argc, char const *argv[])
12 | //{
13 | // int sockfd, portno;
14 | // struct sockaddr_in addr;
15 | //
16 | // portno = 80;
17 | // sockfd = socket(AF_INET, SOCK_STREAM, 0);
18 | // if(sockfd < 0) {
19 | // error("ERROR opening socket");
20 | // }
21 | //
22 | // memset((char*)&addr, 0, sizeof(addr));
23 | //
24 | // addr.sin_port = htons(portno);
25 | // addr.sin_family = AF_INET;
26 | // inet_pton(AF_INET, "183.63.251.70", &addr.sin_addr);
27 | //
28 | // if(connect(sockfd, (struct sockaddr *)&addr, sizeof addr) < 0) {
29 | // close(sockfd);
30 | // error("ERROR connecting to server");
31 | // }
32 | //
33 | // char request[] = "GET /SingleWindow/SingleWindowMessageService.svc/json/ HTTP/1.1\r\nHost: 183.63.251.70\r\nConnection: close\r\n\r\n";
34 | // char response[1024];
35 | //
36 | // send(sockfd, request, sizeof(request), 0);
37 | //
38 | // while(recv(sockfd, response,sizeof(response), 0) > 0) {
39 | // printf(response);
40 | // }
41 | //
42 | // close(sockfd);
43 | // return 0;
44 | //
45 | //}
46 |
47 |
48 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/SocketBasedRequest/CHttpRequest.h:
--------------------------------------------------------------------------------
1 | //
2 | // CHttpRequest.h
3 | // cpapm
4 | //
5 | // Created by yangyouyong on 2018/1/29.
6 | // Copyright © 2018年 welltang. All rights reserved.
7 | //
8 |
9 | #ifndef CHttpRequest_h
10 | #define CHttpRequest_h
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 |
23 | static inline const char *strAppend(const char *, const char *) __attribute__ ((always_inline));
24 | static inline const char *getIpWithDomain(const char *);
25 |
26 |
27 | void error(const char *msg)
28 | {
29 | perror(msg);
30 | exit(1);
31 | }
32 |
33 | typedef void (*ResponseCallBack)(const char*, char *, int);
34 |
35 | static void getRequest(const char* requestIdentifier, const char *protocol, const char *domain, const char *path , ResponseCallBack responseCallBack);
36 | void getRequest(const char* requestIdentifier, const char *protocol, const char *domain, const char *path , ResponseCallBack responseCallBack) {
37 |
38 | int sockfd;
39 | struct sockaddr addr;
40 | sockfd = socket(AF_INET, SOCK_STREAM, 0);
41 | if(sockfd < 0) {
42 | error("ERROR opening socket");
43 | }
44 |
45 | void *identifier = malloc(strlen(requestIdentifier) + 1);
46 | char *cId = (char *)memcpy(identifier, requestIdentifier, strlen(requestIdentifier));
47 | cId[strlen(requestIdentifier)] = '\0';
48 |
49 | memset((char*)&addr, 0, sizeof(addr));
50 |
51 | struct addrinfo *info;
52 |
53 | // 默认80 端口
54 | if (getaddrinfo(domain, "80", NULL, &info) != 0) {
55 | printf("get domain error");
56 | }
57 | addr = *info->ai_addr;
58 |
59 | if(connect(sockfd, &addr, sizeof addr) < 0) {
60 | close(sockfd);
61 | error("ERROR connecting to server");
62 | }
63 |
64 |
65 | // format request eg: "GET /ip HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nUser-Agent: runscope/0.1\r\nHost: httpbin.org\r\nContent-Length: 0\r\n\r\n";
66 |
67 | const char *request = strAppend(NULL,(const char *)"GET ");
68 | request = strAppend(request, path); // path contains parms
69 | request = strAppend(request, " HTTP/1.1\r\n"); // cat protocol
70 | request = strAppend(request, "Host:"); // cat host
71 | request = strAppend(request, domain);
72 | request = strAppend(request, "\r\n");
73 | request = strAppend(request, "Connection: close\r\n\r\n");
74 |
75 | char response[1024];
76 | char splitResponse[1024];
77 | send(sockfd, request, strlen(request), 0);
78 |
79 | while(recv(sockfd, response,sizeof(response), 0) > 0) {
80 | // parse first line
81 | // parse headers
82 | // 倒序查找最后一组 \r\n 的位置 slice body
83 | printf("response: %s\n",response);
84 |
85 | ////////////////////////parse body begin/////////////////////
86 |
87 | char *pstr = NULL;
88 |
89 | strncpy(splitResponse, response, strlen(response));
90 | char *separator = "\r";
91 | int startIndex = 0;
92 | int endIndex = 0;
93 |
94 | char charlist[1024];
95 | int i = 0;
96 | char *substr= strtok(response, separator);
97 | while (substr != NULL) {
98 | strcpy(charlist,substr);
99 | startIndex += strlen(substr);
100 | substr = strtok(NULL,separator);
101 | int responseLength = strlen(response);
102 | if (startIndex < responseLength - 2) {
103 | char nextTwoString[3];
104 | nextTwoString[2] = '\0';
105 | strncpy(nextTwoString, response, startIndex);
106 | printf("nextTwo:%s",nextTwoString);
107 | if (strcmp(nextTwoString, "\r\n") == 0) {
108 | printf("bodybegin");
109 | strncpy(charlist, response, strlen(response) - startIndex);
110 | charlist[strlen(response) - startIndex + 1] = '\0';
111 | }
112 | }
113 | i ++;
114 | }
115 |
116 |
117 | // pstr = strtok((char *)temp, "\r\n");
118 | // while (pstr != NULL) {
119 | //
120 | // pstr = strtok((char *)temp, "\r\n");
121 | // }
122 | printf("finilized body:%s",charlist);
123 | printf("startIndex: %d",startIndex);
124 | printf("length: %d",strlen(splitResponse));
125 | i = strlen(charlist);
126 | while (i > 0) {
127 | char str = charlist[i];
128 | if (str == '}') {
129 | endIndex = i;
130 | break;
131 | }
132 | i --;
133 | }
134 | printf("endIndex: %d",endIndex);
135 | int bodyLenght = endIndex - startIndex;
136 | char destiny[1024];
137 | strncpy(destiny , charlist, strlen(splitResponse) - endIndex);
138 | destiny[bodyLenght + 1] = '\0';
139 | // strncpy(charlist, response, strlen(response) - startIndex);
140 | // char *ss = strstr((char *)response, "\n\r");
141 |
142 | ////////////////////////parse body end/////////////////////
143 |
144 | // 解析response header
145 | if (responseCallBack) {
146 | responseCallBack((const char *)cId, destiny, 0); // append data outside
147 | }
148 | }
149 |
150 | if (responseCallBack) {
151 | responseCallBack((const char *)cId, NULL, 1); // append data outside
152 | }
153 |
154 | close(sockfd);
155 |
156 | }
157 |
158 | const char* strAppend(const char *s1, const char *s2)
159 | {
160 | if (s1 == NULL) {
161 | void *result = malloc(strlen(s2)+1);
162 | strcpy((char *)result, s2);
163 | return (char *)result;
164 | }
165 | void *result = malloc(strlen(s1)+strlen(s2)+1);
166 | if (result == NULL) exit (1);
167 |
168 | strcpy((char *)result, s1);
169 | strcat((char *)result, s2);
170 |
171 | return (char *)result;
172 | }
173 |
174 | const char *getIpWithDomain(const char *domain) {
175 | struct hostent *hs;
176 | struct sockaddr_in server;
177 | hs = gethostbyname(domain);
178 | if (hs != NULL) {
179 | server.sin_addr = *((struct in_addr*)hs->h_addr_list[0]);
180 | return inet_ntoa(server.sin_addr);
181 | }
182 | return NULL;
183 | }
184 | //static void syncGetRequest(const char *protocol, const char *domain, const char *path);
185 |
186 | #endif /* CHttpRequest_h */
187 |
--------------------------------------------------------------------------------
/cpapm/APM/Net/SocketBasedRequest/HTTPRequest.hpp:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPRequest
3 | //
4 |
5 | #pragma once
6 |
7 | #include
8 | #include
9 | #include
10 | #include