UNPKG

4.98 kBPlain TextView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#import "RCTReconnectingWebSocket.h"
9
10#import <React/RCTConvert.h>
11#import <React/RCTDefines.h>
12
13#if __has_include(<React/fishhook.h>)
14#import <React/fishhook.h>
15#else
16#import <fishhook/fishhook.h>
17#endif
18
19#if __has_include(<os/log.h>) && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100300 /* __IPHONE_10_3 */
20#import <os/log.h>
21#endif /* __IPHONE_10_3 */
22
23#import "RCTSRWebSocket.h"
24
25#if RCT_DEV // Only supported in dev mode
26
27#if __has_include(<os/log.h>) && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100300 /* __IPHONE_10_3 */
28
29// From https://github.com/apple/swift/blob/ad40c770bfe372f879b530443a3d94761fe258a6/stdlib/public/SDK/os/os_log.m
30typedef struct os_log_pack_s {
31 uint64_t olp_continuous_time;
32 struct timespec olp_wall_time;
33 const void *olp_mh;
34 const void *olp_pc;
35 const char *olp_format;
36 uint8_t olp_data[0];
37} os_log_pack_s, *os_log_pack_t;
38
39static void (*orig__nwlog_pack)(os_log_pack_t pack, os_log_type_t logType);
40
41static void my__nwlog_pack(os_log_pack_t pack, os_log_type_t logType)
42{
43 if (logType == OS_LOG_TYPE_ERROR && strstr(pack->olp_format, "Connection has no connected handler") == NULL) {
44 orig__nwlog_pack(pack, logType);
45 }
46}
47
48#endif /* __IPHONE_10_3 */
49
50static void (*orig_nwlog_legacy_v)(int, char*, va_list);
51
52static void my_nwlog_legacy_v(int level, char *format, va_list args) {
53 static const uint buffer_size = 256;
54 static char buffer[buffer_size];
55 va_list copy;
56 va_copy(copy, args);
57 vsnprintf(buffer, buffer_size, format, copy);
58 va_end(copy);
59
60 if (strstr(buffer, "nw_connection_get_connected_socket_block_invoke") == NULL &&
61 strstr(buffer, "Connection has no connected handler") == NULL) {
62 orig_nwlog_legacy_v(level, format, args);
63 }
64}
65
66#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
67
68static void (*orig_os_log_error_impl)(void *dso, os_log_t log, os_log_type_t type, const char *format, uint8_t *buf, uint32_t size);
69
70static void my_os_log_error_impl(void *dso, os_log_t log, os_log_type_t type, const char *format, uint8_t *buf, uint32_t size)
71{
72 if (strstr(format, "TCP Conn %p Failed : error %ld:%d") == NULL) {
73 orig_os_log_error_impl(dso, log, type, format, buf, size);
74 }
75}
76
77#endif /* __IPHONE_11_0 */
78
79@interface RCTReconnectingWebSocket () <RCTSRWebSocketDelegate>
80@end
81
82@implementation RCTReconnectingWebSocket {
83 NSURL *_url;
84 RCTSRWebSocket *_socket;
85}
86
87+ (void)load
88{
89 static dispatch_once_t onceToken;
90 dispatch_once(&onceToken, ^{
91 rebind_symbols((struct rebinding[1]){
92 {"nwlog_legacy_v", my_nwlog_legacy_v, (void *)&orig_nwlog_legacy_v}
93 }, 1);
94#if __has_include(<os/log.h>) && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100300 /* __IPHONE_10_3 */
95 rebind_symbols((struct rebinding[1]){
96 {"__nwlog_pack", my__nwlog_pack, (void *)&orig__nwlog_pack}
97 }, 1);
98#endif /* __IPHONE_10_3 */
99#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
100 rebind_symbols((struct rebinding[1]){
101 {"_os_log_error_impl", my_os_log_error_impl, (void *)&orig_os_log_error_impl}
102 }, 1);
103#endif /* __IPHONE_11_0 */
104 });
105}
106
107- (instancetype)initWithURL:(NSURL *)url queue:(dispatch_queue_t)queue
108{
109 if (self = [super init]) {
110 _url = url;
111 _delegateDispatchQueue = queue;
112 }
113 return self;
114}
115
116- (instancetype)initWithURL:(NSURL *)url
117{
118 return [self initWithURL:url queue:dispatch_get_main_queue()];
119}
120
121- (void)send:(id)data
122{
123 [_socket send:data];
124}
125
126- (void)start
127{
128 [self stop];
129 _socket = [[RCTSRWebSocket alloc] initWithURL:_url];
130 _socket.delegate = self;
131 [_socket setDelegateDispatchQueue:_delegateDispatchQueue];
132 [_socket open];
133}
134
135- (void)stop
136{
137 _socket.delegate = nil;
138 [_socket closeWithCode:1000 reason:@"Invalidated"];
139 _socket = nil;
140}
141
142- (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message
143{
144 [_delegate reconnectingWebSocket:self didReceiveMessage:message];
145}
146
147- (void)reconnect
148{
149 __weak RCTSRWebSocket *socket = _socket;
150 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
151 [self start];
152 if (!socket) {
153 [self reconnect];
154 }
155 });
156}
157
158- (void)webSocketDidOpen:(RCTSRWebSocket *)webSocket
159{
160 [_delegate reconnectingWebSocketDidOpen:self];
161}
162
163- (void)webSocket:(RCTSRWebSocket *)webSocket didFailWithError:(NSError *)error
164{
165 [_delegate reconnectingWebSocketDidClose:self];
166 [self reconnect];
167}
168
169- (void)webSocket:(RCTSRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
170{
171 [_delegate reconnectingWebSocketDidClose:self];
172 [self reconnect];
173}
174
175@end
176
177#endif