Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pmbaty | 1 | // |
2 | // GCDAsyncSocket.h |
||
3 | // |
||
4 | // This class is in the public domain. |
||
5 | // Originally created by Robbie Hanson in Q3 2010. |
||
6 | // Updated and maintained by Deusty LLC and the Apple development community. |
||
7 | // |
||
8 | // https://github.com/robbiehanson/CocoaAsyncSocket |
||
9 | // |
||
10 | |||
11 | #import <Foundation/Foundation.h> |
||
12 | #import <Security/Security.h> |
||
13 | #import <Security/SecureTransport.h> |
||
14 | #import <dispatch/dispatch.h> |
||
15 | #import <Availability.h> |
||
16 | |||
17 | #include <sys/socket.h> // AF_INET, AF_INET6 |
||
18 | |||
19 | @class GCDAsyncReadPacket; |
||
20 | @class GCDAsyncWritePacket; |
||
21 | @class GCDAsyncSocketPreBuffer; |
||
22 | @protocol GCDAsyncSocketDelegate; |
||
23 | |||
24 | NS_ASSUME_NONNULL_BEGIN |
||
25 | |||
26 | extern NSString *const GCDAsyncSocketException; |
||
27 | extern NSString *const GCDAsyncSocketErrorDomain; |
||
28 | |||
29 | extern NSString *const GCDAsyncSocketQueueName; |
||
30 | extern NSString *const GCDAsyncSocketThreadName; |
||
31 | |||
32 | extern NSString *const GCDAsyncSocketManuallyEvaluateTrust; |
||
33 | #if TARGET_OS_IPHONE |
||
34 | extern NSString *const GCDAsyncSocketUseCFStreamForTLS; |
||
35 | #endif |
||
36 | #define GCDAsyncSocketSSLPeerName (NSString *)kCFStreamSSLPeerName |
||
37 | #define GCDAsyncSocketSSLCertificates (NSString *)kCFStreamSSLCertificates |
||
38 | #define GCDAsyncSocketSSLIsServer (NSString *)kCFStreamSSLIsServer |
||
39 | extern NSString *const GCDAsyncSocketSSLPeerID; |
||
40 | extern NSString *const GCDAsyncSocketSSLProtocolVersionMin; |
||
41 | extern NSString *const GCDAsyncSocketSSLProtocolVersionMax; |
||
42 | extern NSString *const GCDAsyncSocketSSLSessionOptionFalseStart; |
||
43 | extern NSString *const GCDAsyncSocketSSLSessionOptionSendOneByteRecord; |
||
44 | extern NSString *const GCDAsyncSocketSSLCipherSuites; |
||
45 | extern NSString *const GCDAsyncSocketSSLALPN; |
||
46 | #if !TARGET_OS_IPHONE |
||
47 | extern NSString *const GCDAsyncSocketSSLDiffieHellmanParameters; |
||
48 | #endif |
||
49 | |||
50 | #define GCDAsyncSocketLoggingContext 65535 |
||
51 | |||
52 | |||
53 | typedef NS_ERROR_ENUM(GCDAsyncSocketErrorDomain, GCDAsyncSocketError) { |
||
54 | GCDAsyncSocketNoError = 0, // Never used |
||
55 | GCDAsyncSocketBadConfigError, // Invalid configuration |
||
56 | GCDAsyncSocketBadParamError, // Invalid parameter was passed |
||
57 | GCDAsyncSocketConnectTimeoutError, // A connect operation timed out |
||
58 | GCDAsyncSocketReadTimeoutError, // A read operation timed out |
||
59 | GCDAsyncSocketWriteTimeoutError, // A write operation timed out |
||
60 | GCDAsyncSocketReadMaxedOutError, // Reached set maxLength without completing |
||
61 | GCDAsyncSocketClosedError, // The remote peer closed the connection |
||
62 | GCDAsyncSocketOtherError, // Description provided in userInfo |
||
63 | }; |
||
64 | |||
65 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
66 | #pragma mark - |
||
67 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
68 | |||
69 | |||
70 | @interface GCDAsyncSocket : NSObject |
||
71 | |||
72 | /** |
||
73 | * GCDAsyncSocket uses the standard delegate paradigm, |
||
74 | * but executes all delegate callbacks on a given delegate dispatch queue. |
||
75 | * This allows for maximum concurrency, while at the same time providing easy thread safety. |
||
76 | * |
||
77 | * You MUST set a delegate AND delegate dispatch queue before attempting to |
||
78 | * use the socket, or you will get an error. |
||
79 | * |
||
80 | * The socket queue is optional. |
||
81 | * If you pass NULL, GCDAsyncSocket will automatically create it's own socket queue. |
||
82 | * If you choose to provide a socket queue, the socket queue must not be a concurrent queue. |
||
83 | * If you choose to provide a socket queue, and the socket queue has a configured target queue, |
||
84 | * then please see the discussion for the method markSocketQueueTargetQueue. |
||
85 | * |
||
86 | * The delegate queue and socket queue can optionally be the same. |
||
87 | **/ |
||
88 | - (instancetype)init; |
||
89 | - (instancetype)initWithSocketQueue:(nullable dispatch_queue_t)sq; |
||
90 | - (instancetype)initWithDelegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq; |
||
91 | - (instancetype)initWithDelegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq NS_DESIGNATED_INITIALIZER; |
||
92 | |||
93 | /** |
||
94 | * Create GCDAsyncSocket from already connect BSD socket file descriptor |
||
95 | **/ |
||
96 | + (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD socketQueue:(nullable dispatch_queue_t)sq error:(NSError**)error; |
||
97 | |||
98 | + (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq error:(NSError**)error; |
||
99 | |||
100 | + (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq error:(NSError **)error; |
||
101 | |||
102 | #pragma mark Configuration |
||
103 | |||
104 | @property (atomic, weak, readwrite, nullable) id<GCDAsyncSocketDelegate> delegate; |
||
105 | #if OS_OBJECT_USE_OBJC |
||
106 | @property (atomic, strong, readwrite, nullable) dispatch_queue_t delegateQueue; |
||
107 | #else |
||
108 | @property (atomic, assign, readwrite, nullable) dispatch_queue_t delegateQueue; |
||
109 | #endif |
||
110 | |||
111 | - (void)getDelegate:(id<GCDAsyncSocketDelegate> __nullable * __nullable)delegatePtr delegateQueue:(dispatch_queue_t __nullable * __nullable)delegateQueuePtr; |
||
112 | - (void)setDelegate:(nullable id<GCDAsyncSocketDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue; |
||
113 | |||
114 | /** |
||
115 | * If you are setting the delegate to nil within the delegate's dealloc method, |
||
116 | * you may need to use the synchronous versions below. |
||
117 | **/ |
||
118 | - (void)synchronouslySetDelegate:(nullable id<GCDAsyncSocketDelegate>)delegate; |
||
119 | - (void)synchronouslySetDelegateQueue:(nullable dispatch_queue_t)delegateQueue; |
||
120 | - (void)synchronouslySetDelegate:(nullable id<GCDAsyncSocketDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue; |
||
121 | |||
122 | /** |
||
123 | * By default, both IPv4 and IPv6 are enabled. |
||
124 | * |
||
125 | * For accepting incoming connections, this means GCDAsyncSocket automatically supports both protocols, |
||
126 | * and can simulataneously accept incoming connections on either protocol. |
||
127 | * |
||
128 | * For outgoing connections, this means GCDAsyncSocket can connect to remote hosts running either protocol. |
||
129 | * If a DNS lookup returns only IPv4 results, GCDAsyncSocket will automatically use IPv4. |
||
130 | * If a DNS lookup returns only IPv6 results, GCDAsyncSocket will automatically use IPv6. |
||
131 | * If a DNS lookup returns both IPv4 and IPv6 results, the preferred protocol will be chosen. |
||
132 | * By default, the preferred protocol is IPv4, but may be configured as desired. |
||
133 | **/ |
||
134 | |||
135 | @property (atomic, assign, readwrite, getter=isIPv4Enabled) BOOL IPv4Enabled; |
||
136 | @property (atomic, assign, readwrite, getter=isIPv6Enabled) BOOL IPv6Enabled; |
||
137 | |||
138 | @property (atomic, assign, readwrite, getter=isIPv4PreferredOverIPv6) BOOL IPv4PreferredOverIPv6; |
||
139 | |||
140 | /** |
||
141 | * When connecting to both IPv4 and IPv6 using Happy Eyeballs (RFC 6555) https://tools.ietf.org/html/rfc6555 |
||
142 | * this is the delay between connecting to the preferred protocol and the fallback protocol. |
||
143 | * |
||
144 | * Defaults to 300ms. |
||
145 | **/ |
||
146 | @property (atomic, assign, readwrite) NSTimeInterval alternateAddressDelay; |
||
147 | |||
148 | /** |
||
149 | * User data allows you to associate arbitrary information with the socket. |
||
150 | * This data is not used internally by socket in any way. |
||
151 | **/ |
||
152 | @property (atomic, strong, readwrite, nullable) id userData; |
||
153 | |||
154 | #pragma mark Accepting |
||
155 | |||
156 | /** |
||
157 | * Tells the socket to begin listening and accepting connections on the given port. |
||
158 | * When a connection is accepted, a new instance of GCDAsyncSocket will be spawned to handle it, |
||
159 | * and the socket:didAcceptNewSocket: delegate method will be invoked. |
||
160 | * |
||
161 | * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc) |
||
162 | **/ |
||
163 | - (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr; |
||
164 | |||
165 | /** |
||
166 | * This method is the same as acceptOnPort:error: with the |
||
167 | * additional option of specifying which interface to listen on. |
||
168 | * |
||
169 | * For example, you could specify that the socket should only accept connections over ethernet, |
||
170 | * and not other interfaces such as wifi. |
||
171 | * |
||
172 | * The interface may be specified by name (e.g. "en1" or "lo0") or by IP address (e.g. "192.168.4.34"). |
||
173 | * You may also use the special strings "localhost" or "loopback" to specify that |
||
174 | * the socket only accept connections from the local machine. |
||
175 | * |
||
176 | * You can see the list of interfaces via the command line utility "ifconfig", |
||
177 | * or programmatically via the getifaddrs() function. |
||
178 | * |
||
179 | * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method. |
||
180 | **/ |
||
181 | - (BOOL)acceptOnInterface:(nullable NSString *)interface port:(uint16_t)port error:(NSError **)errPtr; |
||
182 | |||
183 | /** |
||
184 | * Tells the socket to begin listening and accepting connections on the unix domain at the given url. |
||
185 | * When a connection is accepted, a new instance of GCDAsyncSocket will be spawned to handle it, |
||
186 | * and the socket:didAcceptNewSocket: delegate method will be invoked. |
||
187 | * |
||
188 | * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc) |
||
189 | **/ |
||
190 | - (BOOL)acceptOnUrl:(NSURL *)url error:(NSError **)errPtr; |
||
191 | |||
192 | #pragma mark Connecting |
||
193 | |||
194 | /** |
||
195 | * Connects to the given host and port. |
||
196 | * |
||
197 | * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: |
||
198 | * and uses the default interface, and no timeout. |
||
199 | **/ |
||
200 | - (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr; |
||
201 | |||
202 | /** |
||
203 | * Connects to the given host and port with an optional timeout. |
||
204 | * |
||
205 | * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: and uses the default interface. |
||
206 | **/ |
||
207 | - (BOOL)connectToHost:(NSString *)host |
||
208 | onPort:(uint16_t)port |
||
209 | withTimeout:(NSTimeInterval)timeout |
||
210 | error:(NSError **)errPtr; |
||
211 | |||
212 | /** |
||
213 | * Connects to the given host & port, via the optional interface, with an optional timeout. |
||
214 | * |
||
215 | * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2"). |
||
216 | * The host may also be the special strings "localhost" or "loopback" to specify connecting |
||
217 | * to a service on the local machine. |
||
218 | * |
||
219 | * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). |
||
220 | * The interface may also be used to specify the local port (see below). |
||
221 | * |
||
222 | * To not time out use a negative time interval. |
||
223 | * |
||
224 | * This method will return NO if an error is detected, and set the error pointer (if one was given). |
||
225 | * Possible errors would be a nil host, invalid interface, or socket is already connected. |
||
226 | * |
||
227 | * If no errors are detected, this method will start a background connect operation and immediately return YES. |
||
228 | * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable. |
||
229 | * |
||
230 | * Since this class supports queued reads and writes, you can immediately start reading and/or writing. |
||
231 | * All read/write operations will be queued, and upon socket connection, |
||
232 | * the operations will be dequeued and processed in order. |
||
233 | * |
||
234 | * The interface may optionally contain a port number at the end of the string, separated by a colon. |
||
235 | * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end) |
||
236 | * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424". |
||
237 | * To specify only local port: ":8082". |
||
238 | * Please note this is an advanced feature, and is somewhat hidden on purpose. |
||
239 | * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection. |
||
240 | * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere. |
||
241 | * Local ports do NOT need to match remote ports. In fact, they almost never do. |
||
242 | * This feature is here for networking professionals using very advanced techniques. |
||
243 | **/ |
||
244 | - (BOOL)connectToHost:(NSString *)host |
||
245 | onPort:(uint16_t)port |
||
246 | viaInterface:(nullable NSString *)interface |
||
247 | withTimeout:(NSTimeInterval)timeout |
||
248 | error:(NSError **)errPtr; |
||
249 | |||
250 | /** |
||
251 | * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object. |
||
252 | * For example, a NSData object returned from NSNetService's addresses method. |
||
253 | * |
||
254 | * If you have an existing struct sockaddr you can convert it to a NSData object like so: |
||
255 | * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; |
||
256 | * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; |
||
257 | * |
||
258 | * This method invokes connectToAddress:remoteAddr viaInterface:nil withTimeout:-1 error:errPtr. |
||
259 | **/ |
||
260 | - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; |
||
261 | |||
262 | /** |
||
263 | * This method is the same as connectToAddress:error: with an additional timeout option. |
||
264 | * To not time out use a negative time interval, or simply use the connectToAddress:error: method. |
||
265 | **/ |
||
266 | - (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr; |
||
267 | |||
268 | /** |
||
269 | * Connects to the given address, using the specified interface and timeout. |
||
270 | * |
||
271 | * The address is specified as a sockaddr structure wrapped in a NSData object. |
||
272 | * For example, a NSData object returned from NSNetService's addresses method. |
||
273 | * |
||
274 | * If you have an existing struct sockaddr you can convert it to a NSData object like so: |
||
275 | * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; |
||
276 | * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; |
||
277 | * |
||
278 | * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). |
||
279 | * The interface may also be used to specify the local port (see below). |
||
280 | * |
||
281 | * The timeout is optional. To not time out use a negative time interval. |
||
282 | * |
||
283 | * This method will return NO if an error is detected, and set the error pointer (if one was given). |
||
284 | * Possible errors would be a nil host, invalid interface, or socket is already connected. |
||
285 | * |
||
286 | * If no errors are detected, this method will start a background connect operation and immediately return YES. |
||
287 | * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable. |
||
288 | * |
||
289 | * Since this class supports queued reads and writes, you can immediately start reading and/or writing. |
||
290 | * All read/write operations will be queued, and upon socket connection, |
||
291 | * the operations will be dequeued and processed in order. |
||
292 | * |
||
293 | * The interface may optionally contain a port number at the end of the string, separated by a colon. |
||
294 | * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end) |
||
295 | * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424". |
||
296 | * To specify only local port: ":8082". |
||
297 | * Please note this is an advanced feature, and is somewhat hidden on purpose. |
||
298 | * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection. |
||
299 | * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere. |
||
300 | * Local ports do NOT need to match remote ports. In fact, they almost never do. |
||
301 | * This feature is here for networking professionals using very advanced techniques. |
||
302 | **/ |
||
303 | - (BOOL)connectToAddress:(NSData *)remoteAddr |
||
304 | viaInterface:(nullable NSString *)interface |
||
305 | withTimeout:(NSTimeInterval)timeout |
||
306 | error:(NSError **)errPtr; |
||
307 | /** |
||
308 | * Connects to the unix domain socket at the given url, using the specified timeout. |
||
309 | */ |
||
310 | - (BOOL)connectToUrl:(NSURL *)url withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr; |
||
311 | |||
312 | /** |
||
313 | * Iterates over the given NetService's addresses in order, and invokes connectToAddress:error:. Stops at the |
||
314 | * first invocation that succeeds and returns YES; otherwise returns NO. |
||
315 | */ |
||
316 | - (BOOL)connectToNetService:(NSNetService *)netService error:(NSError **)errPtr; |
||
317 | |||
318 | #pragma mark Disconnecting |
||
319 | |||
320 | /** |
||
321 | * Disconnects immediately (synchronously). Any pending reads or writes are dropped. |
||
322 | * |
||
323 | * If the socket is not already disconnected, an invocation to the socketDidDisconnect:withError: delegate method |
||
324 | * will be queued onto the delegateQueue asynchronously (behind any previously queued delegate methods). |
||
325 | * In other words, the disconnected delegate method will be invoked sometime shortly after this method returns. |
||
326 | * |
||
327 | * Please note the recommended way of releasing a GCDAsyncSocket instance (e.g. in a dealloc method) |
||
328 | * [asyncSocket setDelegate:nil]; |
||
329 | * [asyncSocket disconnect]; |
||
330 | * [asyncSocket release]; |
||
331 | * |
||
332 | * If you plan on disconnecting the socket, and then immediately asking it to connect again, |
||
333 | * you'll likely want to do so like this: |
||
334 | * [asyncSocket setDelegate:nil]; |
||
335 | * [asyncSocket disconnect]; |
||
336 | * [asyncSocket setDelegate:self]; |
||
337 | * [asyncSocket connect...]; |
||
338 | **/ |
||
339 | - (void)disconnect; |
||
340 | |||
341 | /** |
||
342 | * Disconnects after all pending reads have completed. |
||
343 | * After calling this, the read and write methods will do nothing. |
||
344 | * The socket will disconnect even if there are still pending writes. |
||
345 | **/ |
||
346 | - (void)disconnectAfterReading; |
||
347 | |||
348 | /** |
||
349 | * Disconnects after all pending writes have completed. |
||
350 | * After calling this, the read and write methods will do nothing. |
||
351 | * The socket will disconnect even if there are still pending reads. |
||
352 | **/ |
||
353 | - (void)disconnectAfterWriting; |
||
354 | |||
355 | /** |
||
356 | * Disconnects after all pending reads and writes have completed. |
||
357 | * After calling this, the read and write methods will do nothing. |
||
358 | **/ |
||
359 | - (void)disconnectAfterReadingAndWriting; |
||
360 | |||
361 | #pragma mark Diagnostics |
||
362 | |||
363 | /** |
||
364 | * Returns whether the socket is disconnected or connected. |
||
365 | * |
||
366 | * A disconnected socket may be recycled. |
||
367 | * That is, it can be used again for connecting or listening. |
||
368 | * |
||
369 | * If a socket is in the process of connecting, it may be neither disconnected nor connected. |
||
370 | **/ |
||
371 | @property (atomic, readonly) BOOL isDisconnected; |
||
372 | @property (atomic, readonly) BOOL isConnected; |
||
373 | |||
374 | /** |
||
375 | * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected. |
||
376 | * The host will be an IP address. |
||
377 | **/ |
||
378 | @property (atomic, readonly, nullable) NSString *connectedHost; |
||
379 | @property (atomic, readonly) uint16_t connectedPort; |
||
380 | @property (atomic, readonly, nullable) NSURL *connectedUrl; |
||
381 | |||
382 | @property (atomic, readonly, nullable) NSString *localHost; |
||
383 | @property (atomic, readonly) uint16_t localPort; |
||
384 | |||
385 | /** |
||
386 | * Returns the local or remote address to which this socket is connected, |
||
387 | * specified as a sockaddr structure wrapped in a NSData object. |
||
388 | * |
||
389 | * @seealso connectedHost |
||
390 | * @seealso connectedPort |
||
391 | * @seealso localHost |
||
392 | * @seealso localPort |
||
393 | **/ |
||
394 | @property (atomic, readonly, nullable) NSData *connectedAddress; |
||
395 | @property (atomic, readonly, nullable) NSData *localAddress; |
||
396 | |||
397 | /** |
||
398 | * Returns whether the socket is IPv4 or IPv6. |
||
399 | * An accepting socket may be both. |
||
400 | **/ |
||
401 | @property (atomic, readonly) BOOL isIPv4; |
||
402 | @property (atomic, readonly) BOOL isIPv6; |
||
403 | |||
404 | /** |
||
405 | * Returns whether or not the socket has been secured via SSL/TLS. |
||
406 | * |
||
407 | * See also the startTLS method. |
||
408 | **/ |
||
409 | @property (atomic, readonly) BOOL isSecure; |
||
410 | |||
411 | #pragma mark Reading |
||
412 | |||
413 | // The readData and writeData methods won't block (they are asynchronous). |
||
414 | // |
||
415 | // When a read is complete the socket:didReadData:withTag: delegate method is dispatched on the delegateQueue. |
||
416 | // When a write is complete the socket:didWriteDataWithTag: delegate method is dispatched on the delegateQueue. |
||
417 | // |
||
418 | // You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.) |
||
419 | // If a read/write opertion times out, the corresponding "socket:shouldTimeout..." delegate method |
||
420 | // is called to optionally allow you to extend the timeout. |
||
421 | // Upon a timeout, the "socket:didDisconnectWithError:" method is called |
||
422 | // |
||
423 | // The tag is for your convenience. |
||
424 | // You can use it as an array index, step number, state id, pointer, etc. |
||
425 | |||
426 | /** |
||
427 | * Reads the first available bytes that become available on the socket. |
||
428 | * |
||
429 | * If the timeout value is negative, the read operation will not use a timeout. |
||
430 | **/ |
||
431 | - (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag; |
||
432 | |||
433 | /** |
||
434 | * Reads the first available bytes that become available on the socket. |
||
435 | * The bytes will be appended to the given byte buffer starting at the given offset. |
||
436 | * The given buffer will automatically be increased in size if needed. |
||
437 | * |
||
438 | * If the timeout value is negative, the read operation will not use a timeout. |
||
439 | * If the buffer is nil, the socket will create a buffer for you. |
||
440 | * |
||
441 | * If the bufferOffset is greater than the length of the given buffer, |
||
442 | * the method will do nothing, and the delegate will not be called. |
||
443 | * |
||
444 | * If you pass a buffer, you must not alter it in any way while the socket is using it. |
||
445 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. |
||
446 | * That is, it will reference the bytes that were appended to the given buffer via |
||
447 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. |
||
448 | **/ |
||
449 | - (void)readDataWithTimeout:(NSTimeInterval)timeout |
||
450 | buffer:(nullable NSMutableData *)buffer |
||
451 | bufferOffset:(NSUInteger)offset |
||
452 | tag:(long)tag; |
||
453 | |||
454 | /** |
||
455 | * Reads the first available bytes that become available on the socket. |
||
456 | * The bytes will be appended to the given byte buffer starting at the given offset. |
||
457 | * The given buffer will automatically be increased in size if needed. |
||
458 | * A maximum of length bytes will be read. |
||
459 | * |
||
460 | * If the timeout value is negative, the read operation will not use a timeout. |
||
461 | * If the buffer is nil, a buffer will automatically be created for you. |
||
462 | * If maxLength is zero, no length restriction is enforced. |
||
463 | * |
||
464 | * If the bufferOffset is greater than the length of the given buffer, |
||
465 | * the method will do nothing, and the delegate will not be called. |
||
466 | * |
||
467 | * If you pass a buffer, you must not alter it in any way while the socket is using it. |
||
468 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. |
||
469 | * That is, it will reference the bytes that were appended to the given buffer via |
||
470 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. |
||
471 | **/ |
||
472 | - (void)readDataWithTimeout:(NSTimeInterval)timeout |
||
473 | buffer:(nullable NSMutableData *)buffer |
||
474 | bufferOffset:(NSUInteger)offset |
||
475 | maxLength:(NSUInteger)length |
||
476 | tag:(long)tag; |
||
477 | |||
478 | /** |
||
479 | * Reads the given number of bytes. |
||
480 | * |
||
481 | * If the timeout value is negative, the read operation will not use a timeout. |
||
482 | * |
||
483 | * If the length is 0, this method does nothing and the delegate is not called. |
||
484 | **/ |
||
485 | - (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; |
||
486 | |||
487 | /** |
||
488 | * Reads the given number of bytes. |
||
489 | * The bytes will be appended to the given byte buffer starting at the given offset. |
||
490 | * The given buffer will automatically be increased in size if needed. |
||
491 | * |
||
492 | * If the timeout value is negative, the read operation will not use a timeout. |
||
493 | * If the buffer is nil, a buffer will automatically be created for you. |
||
494 | * |
||
495 | * If the length is 0, this method does nothing and the delegate is not called. |
||
496 | * If the bufferOffset is greater than the length of the given buffer, |
||
497 | * the method will do nothing, and the delegate will not be called. |
||
498 | * |
||
499 | * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. |
||
500 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. |
||
501 | * That is, it will reference the bytes that were appended to the given buffer via |
||
502 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. |
||
503 | **/ |
||
504 | - (void)readDataToLength:(NSUInteger)length |
||
505 | withTimeout:(NSTimeInterval)timeout |
||
506 | buffer:(nullable NSMutableData *)buffer |
||
507 | bufferOffset:(NSUInteger)offset |
||
508 | tag:(long)tag; |
||
509 | |||
510 | /** |
||
511 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. |
||
512 | * |
||
513 | * If the timeout value is negative, the read operation will not use a timeout. |
||
514 | * |
||
515 | * If you pass nil or zero-length data as the "data" parameter, |
||
516 | * the method will do nothing (except maybe print a warning), and the delegate will not be called. |
||
517 | * |
||
518 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. |
||
519 | * If you're developing your own custom protocol, be sure your separator can not occur naturally as |
||
520 | * part of the data between separators. |
||
521 | * For example, imagine you want to send several small documents over a socket. |
||
522 | * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. |
||
523 | * In this particular example, it would be better to use a protocol similar to HTTP with |
||
524 | * a header that includes the length of the document. |
||
525 | * Also be careful that your separator cannot occur naturally as part of the encoding for a character. |
||
526 | * |
||
527 | * The given data (separator) parameter should be immutable. |
||
528 | * For performance reasons, the socket will retain it, not copy it. |
||
529 | * So if it is immutable, don't modify it while the socket is using it. |
||
530 | **/ |
||
531 | - (void)readDataToData:(nullable NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; |
||
532 | |||
533 | /** |
||
534 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. |
||
535 | * The bytes will be appended to the given byte buffer starting at the given offset. |
||
536 | * The given buffer will automatically be increased in size if needed. |
||
537 | * |
||
538 | * If the timeout value is negative, the read operation will not use a timeout. |
||
539 | * If the buffer is nil, a buffer will automatically be created for you. |
||
540 | * |
||
541 | * If the bufferOffset is greater than the length of the given buffer, |
||
542 | * the method will do nothing (except maybe print a warning), and the delegate will not be called. |
||
543 | * |
||
544 | * If you pass a buffer, you must not alter it in any way while the socket is using it. |
||
545 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. |
||
546 | * That is, it will reference the bytes that were appended to the given buffer via |
||
547 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. |
||
548 | * |
||
549 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. |
||
550 | * If you're developing your own custom protocol, be sure your separator can not occur naturally as |
||
551 | * part of the data between separators. |
||
552 | * For example, imagine you want to send several small documents over a socket. |
||
553 | * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. |
||
554 | * In this particular example, it would be better to use a protocol similar to HTTP with |
||
555 | * a header that includes the length of the document. |
||
556 | * Also be careful that your separator cannot occur naturally as part of the encoding for a character. |
||
557 | * |
||
558 | * The given data (separator) parameter should be immutable. |
||
559 | * For performance reasons, the socket will retain it, not copy it. |
||
560 | * So if it is immutable, don't modify it while the socket is using it. |
||
561 | **/ |
||
562 | - (void)readDataToData:(NSData *)data |
||
563 | withTimeout:(NSTimeInterval)timeout |
||
564 | buffer:(nullable NSMutableData *)buffer |
||
565 | bufferOffset:(NSUInteger)offset |
||
566 | tag:(long)tag; |
||
567 | |||
568 | /** |
||
569 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. |
||
570 | * |
||
571 | * If the timeout value is negative, the read operation will not use a timeout. |
||
572 | * |
||
573 | * If maxLength is zero, no length restriction is enforced. |
||
574 | * Otherwise if maxLength bytes are read without completing the read, |
||
575 | * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError. |
||
576 | * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. |
||
577 | * |
||
578 | * If you pass nil or zero-length data as the "data" parameter, |
||
579 | * the method will do nothing (except maybe print a warning), and the delegate will not be called. |
||
580 | * If you pass a maxLength parameter that is less than the length of the data parameter, |
||
581 | * the method will do nothing (except maybe print a warning), and the delegate will not be called. |
||
582 | * |
||
583 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. |
||
584 | * If you're developing your own custom protocol, be sure your separator can not occur naturally as |
||
585 | * part of the data between separators. |
||
586 | * For example, imagine you want to send several small documents over a socket. |
||
587 | * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. |
||
588 | * In this particular example, it would be better to use a protocol similar to HTTP with |
||
589 | * a header that includes the length of the document. |
||
590 | * Also be careful that your separator cannot occur naturally as part of the encoding for a character. |
||
591 | * |
||
592 | * The given data (separator) parameter should be immutable. |
||
593 | * For performance reasons, the socket will retain it, not copy it. |
||
594 | * So if it is immutable, don't modify it while the socket is using it. |
||
595 | **/ |
||
596 | - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag; |
||
597 | |||
598 | /** |
||
599 | * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. |
||
600 | * The bytes will be appended to the given byte buffer starting at the given offset. |
||
601 | * The given buffer will automatically be increased in size if needed. |
||
602 | * |
||
603 | * If the timeout value is negative, the read operation will not use a timeout. |
||
604 | * If the buffer is nil, a buffer will automatically be created for you. |
||
605 | * |
||
606 | * If maxLength is zero, no length restriction is enforced. |
||
607 | * Otherwise if maxLength bytes are read without completing the read, |
||
608 | * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError. |
||
609 | * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. |
||
610 | * |
||
611 | * If you pass a maxLength parameter that is less than the length of the data (separator) parameter, |
||
612 | * the method will do nothing (except maybe print a warning), and the delegate will not be called. |
||
613 | * If the bufferOffset is greater than the length of the given buffer, |
||
614 | * the method will do nothing (except maybe print a warning), and the delegate will not be called. |
||
615 | * |
||
616 | * If you pass a buffer, you must not alter it in any way while the socket is using it. |
||
617 | * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. |
||
618 | * That is, it will reference the bytes that were appended to the given buffer via |
||
619 | * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. |
||
620 | * |
||
621 | * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. |
||
622 | * If you're developing your own custom protocol, be sure your separator can not occur naturally as |
||
623 | * part of the data between separators. |
||
624 | * For example, imagine you want to send several small documents over a socket. |
||
625 | * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. |
||
626 | * In this particular example, it would be better to use a protocol similar to HTTP with |
||
627 | * a header that includes the length of the document. |
||
628 | * Also be careful that your separator cannot occur naturally as part of the encoding for a character. |
||
629 | * |
||
630 | * The given data (separator) parameter should be immutable. |
||
631 | * For performance reasons, the socket will retain it, not copy it. |
||
632 | * So if it is immutable, don't modify it while the socket is using it. |
||
633 | **/ |
||
634 | - (void)readDataToData:(NSData *)data |
||
635 | withTimeout:(NSTimeInterval)timeout |
||
636 | buffer:(nullable NSMutableData *)buffer |
||
637 | bufferOffset:(NSUInteger)offset |
||
638 | maxLength:(NSUInteger)length |
||
639 | tag:(long)tag; |
||
640 | |||
641 | /** |
||
642 | * Returns progress of the current read, from 0.0 to 1.0, or NaN if no current read (use isnan() to check). |
||
643 | * The parameters "tag", "done" and "total" will be filled in if they aren't NULL. |
||
644 | **/ |
||
645 | - (float)progressOfReadReturningTag:(nullable long *)tagPtr bytesDone:(nullable NSUInteger *)donePtr total:(nullable NSUInteger *)totalPtr; |
||
646 | |||
647 | #pragma mark Writing |
||
648 | |||
649 | /** |
||
650 | * Writes data to the socket, and calls the delegate when finished. |
||
651 | * |
||
652 | * If you pass in nil or zero-length data, this method does nothing and the delegate will not be called. |
||
653 | * If the timeout value is negative, the write operation will not use a timeout. |
||
654 | * |
||
655 | * Thread-Safety Note: |
||
656 | * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while |
||
657 | * the socket is writing it. In other words, it's not safe to alter the data until after the delegate method |
||
658 | * socket:didWriteDataWithTag: is invoked signifying that this particular write operation has completed. |
||
659 | * This is due to the fact that GCDAsyncSocket does NOT copy the data. It simply retains it. |
||
660 | * This is for performance reasons. Often times, if NSMutableData is passed, it is because |
||
661 | * a request/response was built up in memory. Copying this data adds an unwanted/unneeded overhead. |
||
662 | * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket |
||
663 | * completes writing the bytes (which is NOT immediately after this method returns, but rather at a later time |
||
664 | * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. |
||
665 | **/ |
||
666 | - (void)writeData:(nullable NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; |
||
667 | |||
668 | /** |
||
669 | * Returns progress of the current write, from 0.0 to 1.0, or NaN if no current write (use isnan() to check). |
||
670 | * The parameters "tag", "done" and "total" will be filled in if they aren't NULL. |
||
671 | **/ |
||
672 | - (float)progressOfWriteReturningTag:(nullable long *)tagPtr bytesDone:(nullable NSUInteger *)donePtr total:(nullable NSUInteger *)totalPtr; |
||
673 | |||
674 | #pragma mark Security |
||
675 | |||
676 | /** |
||
677 | * Secures the connection using SSL/TLS. |
||
678 | * |
||
679 | * This method may be called at any time, and the TLS handshake will occur after all pending reads and writes |
||
680 | * are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing |
||
681 | * the upgrade to TLS at the same time, without having to wait for the write to finish. |
||
682 | * Any reads or writes scheduled after this method is called will occur over the secured connection. |
||
683 | * |
||
684 | * ==== The available TOP-LEVEL KEYS are: |
||
685 | * |
||
686 | * - GCDAsyncSocketManuallyEvaluateTrust |
||
687 | * The value must be of type NSNumber, encapsulating a BOOL value. |
||
688 | * If you set this to YES, then the underlying SecureTransport system will not evaluate the SecTrustRef of the peer. |
||
689 | * Instead it will pause at the moment evaulation would typically occur, |
||
690 | * and allow us to handle the security evaluation however we see fit. |
||
691 | * So GCDAsyncSocket will invoke the delegate method socket:shouldTrustPeer: passing the SecTrustRef. |
||
692 | * |
||
693 | * Note that if you set this option, then all other configuration keys are ignored. |
||
694 | * Evaluation will be completely up to you during the socket:didReceiveTrust:completionHandler: delegate method. |
||
695 | * |
||
696 | * For more information on trust evaluation see: |
||
697 | * Apple's Technical Note TN2232 - HTTPS Server Trust Evaluation |
||
698 | * https://developer.apple.com/library/ios/technotes/tn2232/_index.html |
||
699 | * |
||
700 | * If unspecified, the default value is NO. |
||
701 | * |
||
702 | * - GCDAsyncSocketUseCFStreamForTLS (iOS only) |
||
703 | * The value must be of type NSNumber, encapsulating a BOOL value. |
||
704 | * By default GCDAsyncSocket will use the SecureTransport layer to perform encryption. |
||
705 | * This gives us more control over the security protocol (many more configuration options), |
||
706 | * plus it allows us to optimize things like sys calls and buffer allocation. |
||
707 | * |
||
708 | * However, if you absolutely must, you can instruct GCDAsyncSocket to use the old-fashioned encryption |
||
709 | * technique by going through the CFStream instead. So instead of using SecureTransport, GCDAsyncSocket |
||
710 | * will instead setup a CFRead/CFWriteStream. And then set the kCFStreamPropertySSLSettings property |
||
711 | * (via CFReadStreamSetProperty / CFWriteStreamSetProperty) and will pass the given options to this method. |
||
712 | * |
||
713 | * Thus all the other keys in the given dictionary will be ignored by GCDAsyncSocket, |
||
714 | * and will passed directly CFReadStreamSetProperty / CFWriteStreamSetProperty. |
||
715 | * For more infomation on these keys, please see the documentation for kCFStreamPropertySSLSettings. |
||
716 | * |
||
717 | * If unspecified, the default value is NO. |
||
718 | * |
||
719 | * ==== The available CONFIGURATION KEYS are: |
||
720 | * |
||
721 | * - kCFStreamSSLPeerName |
||
722 | * The value must be of type NSString. |
||
723 | * It should match the name in the X.509 certificate given by the remote party. |
||
724 | * See Apple's documentation for SSLSetPeerDomainName. |
||
725 | * |
||
726 | * - kCFStreamSSLCertificates |
||
727 | * The value must be of type NSArray. |
||
728 | * See Apple's documentation for SSLSetCertificate. |
||
729 | * |
||
730 | * - kCFStreamSSLIsServer |
||
731 | * The value must be of type NSNumber, encapsulationg a BOOL value. |
||
732 | * See Apple's documentation for SSLCreateContext for iOS. |
||
733 | * This is optional for iOS. If not supplied, a NO value is the default. |
||
734 | * This is not needed for Mac OS X, and the value is ignored. |
||
735 | * |
||
736 | * - GCDAsyncSocketSSLPeerID |
||
737 | * The value must be of type NSData. |
||
738 | * You must set this value if you want to use TLS session resumption. |
||
739 | * See Apple's documentation for SSLSetPeerID. |
||
740 | * |
||
741 | * - GCDAsyncSocketSSLProtocolVersionMin |
||
742 | * - GCDAsyncSocketSSLProtocolVersionMax |
||
743 | * The value(s) must be of type NSNumber, encapsulting a SSLProtocol value. |
||
744 | * See Apple's documentation for SSLSetProtocolVersionMin & SSLSetProtocolVersionMax. |
||
745 | * See also the SSLProtocol typedef. |
||
746 | * |
||
747 | * - GCDAsyncSocketSSLSessionOptionFalseStart |
||
748 | * The value must be of type NSNumber, encapsulating a BOOL value. |
||
749 | * See Apple's documentation for kSSLSessionOptionFalseStart. |
||
750 | * |
||
751 | * - GCDAsyncSocketSSLSessionOptionSendOneByteRecord |
||
752 | * The value must be of type NSNumber, encapsulating a BOOL value. |
||
753 | * See Apple's documentation for kSSLSessionOptionSendOneByteRecord. |
||
754 | * |
||
755 | * - GCDAsyncSocketSSLCipherSuites |
||
756 | * The values must be of type NSArray. |
||
757 | * Each item within the array must be a NSNumber, encapsulating an SSLCipherSuite. |
||
758 | * See Apple's documentation for SSLSetEnabledCiphers. |
||
759 | * See also the SSLCipherSuite typedef. |
||
760 | * |
||
761 | * - GCDAsyncSocketSSLDiffieHellmanParameters (Mac OS X only) |
||
762 | * The value must be of type NSData. |
||
763 | * See Apple's documentation for SSLSetDiffieHellmanParams. |
||
764 | * |
||
765 | * ==== The following UNAVAILABLE KEYS are: (with throw an exception) |
||
766 | * |
||
767 | * - kCFStreamSSLAllowsAnyRoot (UNAVAILABLE) |
||
768 | * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust). |
||
769 | * Corresponding deprecated method: SSLSetAllowsAnyRoot |
||
770 | * |
||
771 | * - kCFStreamSSLAllowsExpiredRoots (UNAVAILABLE) |
||
772 | * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust). |
||
773 | * Corresponding deprecated method: SSLSetAllowsExpiredRoots |
||
774 | * |
||
775 | * - kCFStreamSSLAllowsExpiredCertificates (UNAVAILABLE) |
||
776 | * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust). |
||
777 | * Corresponding deprecated method: SSLSetAllowsExpiredCerts |
||
778 | * |
||
779 | * - kCFStreamSSLValidatesCertificateChain (UNAVAILABLE) |
||
780 | * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust). |
||
781 | * Corresponding deprecated method: SSLSetEnableCertVerify |
||
782 | * |
||
783 | * - kCFStreamSSLLevel (UNAVAILABLE) |
||
784 | * You MUST use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMin instead. |
||
785 | * Corresponding deprecated method: SSLSetProtocolVersionEnabled |
||
786 | * |
||
787 | * |
||
788 | * Please refer to Apple's documentation for corresponding SSLFunctions. |
||
789 | * |
||
790 | * If you pass in nil or an empty dictionary, the default settings will be used. |
||
791 | * |
||
792 | * IMPORTANT SECURITY NOTE: |
||
793 | * The default settings will check to make sure the remote party's certificate is signed by a |
||
794 | * trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired. |
||
795 | * However it will not verify the name on the certificate unless you |
||
796 | * give it a name to verify against via the kCFStreamSSLPeerName key. |
||
797 | * The security implications of this are important to understand. |
||
798 | * Imagine you are attempting to create a secure connection to MySecureServer.com, |
||
799 | * but your socket gets directed to MaliciousServer.com because of a hacked DNS server. |
||
800 | * If you simply use the default settings, and MaliciousServer.com has a valid certificate, |
||
801 | * the default settings will not detect any problems since the certificate is valid. |
||
802 | * To properly secure your connection in this particular scenario you |
||
803 | * should set the kCFStreamSSLPeerName property to "MySecureServer.com". |
||
804 | * |
||
805 | * You can also perform additional validation in socketDidSecure. |
||
806 | **/ |
||
807 | - (void)startTLS:(nullable NSDictionary <NSString*,NSObject*>*)tlsSettings; |
||
808 | |||
809 | #pragma mark Advanced |
||
810 | |||
811 | /** |
||
812 | * Traditionally sockets are not closed until the conversation is over. |
||
813 | * However, it is technically possible for the remote enpoint to close its write stream. |
||
814 | * Our socket would then be notified that there is no more data to be read, |
||
815 | * but our socket would still be writeable and the remote endpoint could continue to receive our data. |
||
816 | * |
||
817 | * The argument for this confusing functionality stems from the idea that a client could shut down its |
||
818 | * write stream after sending a request to the server, thus notifying the server there are to be no further requests. |
||
819 | * In practice, however, this technique did little to help server developers. |
||
820 | * |
||
821 | * To make matters worse, from a TCP perspective there is no way to tell the difference from a read stream close |
||
822 | * and a full socket close. They both result in the TCP stack receiving a FIN packet. The only way to tell |
||
823 | * is by continuing to write to the socket. If it was only a read stream close, then writes will continue to work. |
||
824 | * Otherwise an error will be occur shortly (when the remote end sends us a RST packet). |
||
825 | * |
||
826 | * In addition to the technical challenges and confusion, many high level socket/stream API's provide |
||
827 | * no support for dealing with the problem. If the read stream is closed, the API immediately declares the |
||
828 | * socket to be closed, and shuts down the write stream as well. In fact, this is what Apple's CFStream API does. |
||
829 | * It might sound like poor design at first, but in fact it simplifies development. |
||
830 | * |
||
831 | * The vast majority of the time if the read stream is closed it's because the remote endpoint closed its socket. |
||
832 | * Thus it actually makes sense to close the socket at this point. |
||
833 | * And in fact this is what most networking developers want and expect to happen. |
||
834 | * However, if you are writing a server that interacts with a plethora of clients, |
||
835 | * you might encounter a client that uses the discouraged technique of shutting down its write stream. |
||
836 | * If this is the case, you can set this property to NO, |
||
837 | * and make use of the socketDidCloseReadStream delegate method. |
||
838 | * |
||
839 | * The default value is YES. |
||
840 | **/ |
||
841 | @property (atomic, assign, readwrite) BOOL autoDisconnectOnClosedReadStream; |
||
842 | |||
843 | /** |
||
844 | * GCDAsyncSocket maintains thread safety by using an internal serial dispatch_queue. |
||
845 | * In most cases, the instance creates this queue itself. |
||
846 | * However, to allow for maximum flexibility, the internal queue may be passed in the init method. |
||
847 | * This allows for some advanced options such as controlling socket priority via target queues. |
||
848 | * However, when one begins to use target queues like this, they open the door to some specific deadlock issues. |
||
849 | * |
||
850 | * For example, imagine there are 2 queues: |
||
851 | * dispatch_queue_t socketQueue; |
||
852 | * dispatch_queue_t socketTargetQueue; |
||
853 | * |
||
854 | * If you do this (pseudo-code): |
||
855 | * socketQueue.targetQueue = socketTargetQueue; |
||
856 | * |
||
857 | * Then all socketQueue operations will actually get run on the given socketTargetQueue. |
||
858 | * This is fine and works great in most situations. |
||
859 | * But if you run code directly from within the socketTargetQueue that accesses the socket, |
||
860 | * you could potentially get deadlock. Imagine the following code: |
||
861 | * |
||
862 | * - (BOOL)socketHasSomething |
||
863 | * { |
||
864 | * __block BOOL result = NO; |
||
865 | * dispatch_block_t block = ^{ |
||
866 | * result = [self someInternalMethodToBeRunOnlyOnSocketQueue]; |
||
867 | * } |
||
868 | * if (is_executing_on_queue(socketQueue)) |
||
869 | * block(); |
||
870 | * else |
||
871 | * dispatch_sync(socketQueue, block); |
||
872 | * |
||
873 | * return result; |
||
874 | * } |
||
875 | * |
||
876 | * What happens if you call this method from the socketTargetQueue? The result is deadlock. |
||
877 | * This is because the GCD API offers no mechanism to discover a queue's targetQueue. |
||
878 | * Thus we have no idea if our socketQueue is configured with a targetQueue. |
||
879 | * If we had this information, we could easily avoid deadlock. |
||
880 | * But, since these API's are missing or unfeasible, you'll have to explicitly set it. |
||
881 | * |
||
882 | * IF you pass a socketQueue via the init method, |
||
883 | * AND you've configured the passed socketQueue with a targetQueue, |
||
884 | * THEN you should pass the end queue in the target hierarchy. |
||
885 | * |
||
886 | * For example, consider the following queue hierarchy: |
||
887 | * socketQueue -> ipQueue -> moduleQueue |
||
888 | * |
||
889 | * This example demonstrates priority shaping within some server. |
||
890 | * All incoming client connections from the same IP address are executed on the same target queue. |
||
891 | * And all connections for a particular module are executed on the same target queue. |
||
892 | * Thus, the priority of all networking for the entire module can be changed on the fly. |
||
893 | * Additionally, networking traffic from a single IP cannot monopolize the module. |
||
894 | * |
||
895 | * Here's how you would accomplish something like that: |
||
896 | * - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock |
||
897 | * { |
||
898 | * dispatch_queue_t socketQueue = dispatch_queue_create("", NULL); |
||
899 | * dispatch_queue_t ipQueue = [self ipQueueForAddress:address]; |
||
900 | * |
||
901 | * dispatch_set_target_queue(socketQueue, ipQueue); |
||
902 | * dispatch_set_target_queue(iqQueue, moduleQueue); |
||
903 | * |
||
904 | * return socketQueue; |
||
905 | * } |
||
906 | * - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket |
||
907 | * { |
||
908 | * [clientConnections addObject:newSocket]; |
||
909 | * [newSocket markSocketQueueTargetQueue:moduleQueue]; |
||
910 | * } |
||
911 | * |
||
912 | * Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue. |
||
913 | * This is often NOT the case, as such queues are used solely for execution shaping. |
||
914 | **/ |
||
915 | - (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreConfiguredTargetQueue; |
||
916 | - (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue; |
||
917 | |||
918 | /** |
||
919 | * It's not thread-safe to access certain variables from outside the socket's internal queue. |
||
920 | * |
||
921 | * For example, the socket file descriptor. |
||
922 | * File descriptors are simply integers which reference an index in the per-process file table. |
||
923 | * However, when one requests a new file descriptor (by opening a file or socket), |
||
924 | * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor. |
||
925 | * So if we're not careful, the following could be possible: |
||
926 | * |
||
927 | * - Thread A invokes a method which returns the socket's file descriptor. |
||
928 | * - The socket is closed via the socket's internal queue on thread B. |
||
929 | * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD. |
||
930 | * - Thread A is now accessing/altering the file instead of the socket. |
||
931 | * |
||
932 | * In addition to this, other variables are not actually objects, |
||
933 | * and thus cannot be retained/released or even autoreleased. |
||
934 | * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct. |
||
935 | * |
||
936 | * Although there are internal variables that make it difficult to maintain thread-safety, |
||
937 | * it is important to provide access to these variables |
||
938 | * to ensure this class can be used in a wide array of environments. |
||
939 | * This method helps to accomplish this by invoking the current block on the socket's internal queue. |
||
940 | * The methods below can be invoked from within the block to access |
||
941 | * those generally thread-unsafe internal variables in a thread-safe manner. |
||
942 | * The given block will be invoked synchronously on the socket's internal queue. |
||
943 | * |
||
944 | * If you save references to any protected variables and use them outside the block, you do so at your own peril. |
||
945 | **/ |
||
946 | - (void)performBlock:(dispatch_block_t)block; |
||
947 | |||
948 | /** |
||
949 | * These methods are only available from within the context of a performBlock: invocation. |
||
950 | * See the documentation for the performBlock: method above. |
||
951 | * |
||
952 | * Provides access to the socket's file descriptor(s). |
||
953 | * If the socket is a server socket (is accepting incoming connections), |
||
954 | * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6. |
||
955 | **/ |
||
956 | - (int)socketFD; |
||
957 | - (int)socket4FD; |
||
958 | - (int)socket6FD; |
||
959 | |||
960 | #if TARGET_OS_IPHONE |
||
961 | |||
962 | /** |
||
963 | * These methods are only available from within the context of a performBlock: invocation. |
||
964 | * See the documentation for the performBlock: method above. |
||
965 | * |
||
966 | * Provides access to the socket's internal CFReadStream/CFWriteStream. |
||
967 | * |
||
968 | * These streams are only used as workarounds for specific iOS shortcomings: |
||
969 | * |
||
970 | * - Apple has decided to keep the SecureTransport framework private is iOS. |
||
971 | * This means the only supplied way to do SSL/TLS is via CFStream or some other API layered on top of it. |
||
972 | * Thus, in order to provide SSL/TLS support on iOS we are forced to rely on CFStream, |
||
973 | * instead of the preferred and faster and more powerful SecureTransport. |
||
974 | * |
||
975 | * - If a socket doesn't have backgrounding enabled, and that socket is closed while the app is backgrounded, |
||
976 | * Apple only bothers to notify us via the CFStream API. |
||
977 | * The faster and more powerful GCD API isn't notified properly in this case. |
||
978 | * |
||
979 | * See also: (BOOL)enableBackgroundingOnSocket |
||
980 | **/ |
||
981 | - (nullable CFReadStreamRef)readStream; |
||
982 | - (nullable CFWriteStreamRef)writeStream; |
||
983 | |||
984 | /** |
||
985 | * This method is only available from within the context of a performBlock: invocation. |
||
986 | * See the documentation for the performBlock: method above. |
||
987 | * |
||
988 | * Configures the socket to allow it to operate when the iOS application has been backgrounded. |
||
989 | * In other words, this method creates a read & write stream, and invokes: |
||
990 | * |
||
991 | * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); |
||
992 | * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); |
||
993 | * |
||
994 | * Returns YES if successful, NO otherwise. |
||
995 | * |
||
996 | * Note: Apple does not officially support backgrounding server sockets. |
||
997 | * That is, if your socket is accepting incoming connections, Apple does not officially support |
||
998 | * allowing iOS applications to accept incoming connections while an app is backgrounded. |
||
999 | * |
||
1000 | * Example usage: |
||
1001 | * |
||
1002 | * - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port |
||
1003 | * { |
||
1004 | * [asyncSocket performBlock:^{ |
||
1005 | * [asyncSocket enableBackgroundingOnSocket]; |
||
1006 | * }]; |
||
1007 | * } |
||
1008 | **/ |
||
1009 | - (BOOL)enableBackgroundingOnSocket; |
||
1010 | |||
1011 | #endif |
||
1012 | |||
1013 | /** |
||
1014 | * This method is only available from within the context of a performBlock: invocation. |
||
1015 | * See the documentation for the performBlock: method above. |
||
1016 | * |
||
1017 | * Provides access to the socket's SSLContext, if SSL/TLS has been started on the socket. |
||
1018 | **/ |
||
1019 | - (nullable SSLContextRef)sslContext; |
||
1020 | |||
1021 | #pragma mark Utilities |
||
1022 | |||
1023 | /** |
||
1024 | * The address lookup utility used by the class. |
||
1025 | * This method is synchronous, so it's recommended you use it on a background thread/queue. |
||
1026 | * |
||
1027 | * The special strings "localhost" and "loopback" return the loopback address for IPv4 and IPv6. |
||
1028 | * |
||
1029 | * @returns |
||
1030 | * A mutable array with all IPv4 and IPv6 addresses returned by getaddrinfo. |
||
1031 | * The addresses are specifically for TCP connections. |
||
1032 | * You can filter the addresses, if needed, using the other utility methods provided by the class. |
||
1033 | **/ |
||
1034 | + (nullable NSMutableArray *)lookupHost:(NSString *)host port:(uint16_t)port error:(NSError **)errPtr; |
||
1035 | |||
1036 | /** |
||
1037 | * Extracting host and port information from raw address data. |
||
1038 | **/ |
||
1039 | |||
1040 | + (nullable NSString *)hostFromAddress:(NSData *)address; |
||
1041 | + (uint16_t)portFromAddress:(NSData *)address; |
||
1042 | |||
1043 | + (BOOL)isIPv4Address:(NSData *)address; |
||
1044 | + (BOOL)isIPv6Address:(NSData *)address; |
||
1045 | |||
1046 | + (BOOL)getHost:( NSString * __nullable * __nullable)hostPtr port:(nullable uint16_t *)portPtr fromAddress:(NSData *)address; |
||
1047 | |||
1048 | + (BOOL)getHost:(NSString * __nullable * __nullable)hostPtr port:(nullable uint16_t *)portPtr family:(nullable sa_family_t *)afPtr fromAddress:(NSData *)address; |
||
1049 | |||
1050 | /** |
||
1051 | * A few common line separators, for use with the readDataToData:... methods. |
||
1052 | **/ |
||
1053 | + (NSData *)CRLFData; // 0x0D0A |
||
1054 | + (NSData *)CRData; // 0x0D |
||
1055 | + (NSData *)LFData; // 0x0A |
||
1056 | + (NSData *)ZeroData; // 0x00 |
||
1057 | |||
1058 | @end |
||
1059 | |||
1060 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
1061 | #pragma mark - |
||
1062 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
||
1063 | |||
1064 | @protocol GCDAsyncSocketDelegate <NSObject> |
||
1065 | @optional |
||
1066 | |||
1067 | /** |
||
1068 | * This method is called immediately prior to socket:didAcceptNewSocket:. |
||
1069 | * It optionally allows a listening socket to specify the socketQueue for a new accepted socket. |
||
1070 | * If this method is not implemented, or returns NULL, the new accepted socket will create its own default queue. |
||
1071 | * |
||
1072 | * Since you cannot autorelease a dispatch_queue, |
||
1073 | * this method uses the "new" prefix in its name to specify that the returned queue has been retained. |
||
1074 | * |
||
1075 | * Thus you could do something like this in the implementation: |
||
1076 | * return dispatch_queue_create("MyQueue", NULL); |
||
1077 | * |
||
1078 | * If you are placing multiple sockets on the same queue, |
||
1079 | * then care should be taken to increment the retain count each time this method is invoked. |
||
1080 | * |
||
1081 | * For example, your implementation might look something like this: |
||
1082 | * dispatch_retain(myExistingQueue); |
||
1083 | * return myExistingQueue; |
||
1084 | **/ |
||
1085 | - (nullable dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock; |
||
1086 | |||
1087 | /** |
||
1088 | * Called when a socket accepts a connection. |
||
1089 | * Another socket is automatically spawned to handle it. |
||
1090 | * |
||
1091 | * You must retain the newSocket if you wish to handle the connection. |
||
1092 | * Otherwise the newSocket instance will be released and the spawned connection will be closed. |
||
1093 | * |
||
1094 | * By default the new socket will have the same delegate and delegateQueue. |
||
1095 | * You may, of course, change this at any time. |
||
1096 | **/ |
||
1097 | - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket; |
||
1098 | |||
1099 | /** |
||
1100 | * Called when a socket connects and is ready for reading and writing. |
||
1101 | * The host parameter will be an IP address, not a DNS name. |
||
1102 | **/ |
||
1103 | - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port; |
||
1104 | |||
1105 | /** |
||
1106 | * Called when a socket connects and is ready for reading and writing. |
||
1107 | * The host parameter will be an IP address, not a DNS name. |
||
1108 | **/ |
||
1109 | - (void)socket:(GCDAsyncSocket *)sock didConnectToUrl:(NSURL *)url; |
||
1110 | |||
1111 | /** |
||
1112 | * Called when a socket has completed reading the requested data into memory. |
||
1113 | * Not called if there is an error. |
||
1114 | **/ |
||
1115 | - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag; |
||
1116 | |||
1117 | /** |
||
1118 | * Called when a socket has read in data, but has not yet completed the read. |
||
1119 | * This would occur if using readToData: or readToLength: methods. |
||
1120 | * It may be used for things such as updating progress bars. |
||
1121 | **/ |
||
1122 | - (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; |
||
1123 | |||
1124 | /** |
||
1125 | * Called when a socket has completed writing the requested data. Not called if there is an error. |
||
1126 | **/ |
||
1127 | - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag; |
||
1128 | |||
1129 | /** |
||
1130 | * Called when a socket has written some data, but has not yet completed the entire write. |
||
1131 | * It may be used for things such as updating progress bars. |
||
1132 | **/ |
||
1133 | - (void)socket:(GCDAsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; |
||
1134 | |||
1135 | /** |
||
1136 | * Called if a read operation has reached its timeout without completing. |
||
1137 | * This method allows you to optionally extend the timeout. |
||
1138 | * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount. |
||
1139 | * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual. |
||
1140 | * |
||
1141 | * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. |
||
1142 | * The length parameter is the number of bytes that have been read so far for the read operation. |
||
1143 | * |
||
1144 | * Note that this method may be called multiple times for a single read if you return positive numbers. |
||
1145 | **/ |
||
1146 | - (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag |
||
1147 | elapsed:(NSTimeInterval)elapsed |
||
1148 | bytesDone:(NSUInteger)length; |
||
1149 | |||
1150 | /** |
||
1151 | * Called if a write operation has reached its timeout without completing. |
||
1152 | * This method allows you to optionally extend the timeout. |
||
1153 | * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount. |
||
1154 | * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual. |
||
1155 | * |
||
1156 | * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. |
||
1157 | * The length parameter is the number of bytes that have been written so far for the write operation. |
||
1158 | * |
||
1159 | * Note that this method may be called multiple times for a single write if you return positive numbers. |
||
1160 | **/ |
||
1161 | - (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag |
||
1162 | elapsed:(NSTimeInterval)elapsed |
||
1163 | bytesDone:(NSUInteger)length; |
||
1164 | |||
1165 | /** |
||
1166 | * Conditionally called if the read stream closes, but the write stream may still be writeable. |
||
1167 | * |
||
1168 | * This delegate method is only called if autoDisconnectOnClosedReadStream has been set to NO. |
||
1169 | * See the discussion on the autoDisconnectOnClosedReadStream method for more information. |
||
1170 | **/ |
||
1171 | - (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock; |
||
1172 | |||
1173 | /** |
||
1174 | * Called when a socket disconnects with or without error. |
||
1175 | * |
||
1176 | * If you call the disconnect method, and the socket wasn't already disconnected, |
||
1177 | * then an invocation of this delegate method will be enqueued on the delegateQueue |
||
1178 | * before the disconnect method returns. |
||
1179 | * |
||
1180 | * Note: If the GCDAsyncSocket instance is deallocated while it is still connected, |
||
1181 | * and the delegate is not also deallocated, then this method will be invoked, |
||
1182 | * but the sock parameter will be nil. (It must necessarily be nil since it is no longer available.) |
||
1183 | * This is a generally rare, but is possible if one writes code like this: |
||
1184 | * |
||
1185 | * asyncSocket = nil; // I'm implicitly disconnecting the socket |
||
1186 | * |
||
1187 | * In this case it may preferrable to nil the delegate beforehand, like this: |
||
1188 | * |
||
1189 | * asyncSocket.delegate = nil; // Don't invoke my delegate method |
||
1190 | * asyncSocket = nil; // I'm implicitly disconnecting the socket |
||
1191 | * |
||
1192 | * Of course, this depends on how your state machine is configured. |
||
1193 | **/ |
||
1194 | - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err; |
||
1195 | |||
1196 | /** |
||
1197 | * Called after the socket has successfully completed SSL/TLS negotiation. |
||
1198 | * This method is not called unless you use the provided startTLS method. |
||
1199 | * |
||
1200 | * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close, |
||
1201 | * and the socketDidDisconnect:withError: delegate method will be called with the specific SSL error code. |
||
1202 | **/ |
||
1203 | - (void)socketDidSecure:(GCDAsyncSocket *)sock; |
||
1204 | |||
1205 | /** |
||
1206 | * Allows a socket delegate to hook into the TLS handshake and manually validate the peer it's connecting to. |
||
1207 | * |
||
1208 | * This is only called if startTLS is invoked with options that include: |
||
1209 | * - GCDAsyncSocketManuallyEvaluateTrust == YES |
||
1210 | * |
||
1211 | * Typically the delegate will use SecTrustEvaluate (and related functions) to properly validate the peer. |
||
1212 | * |
||
1213 | * Note from Apple's documentation: |
||
1214 | * Because [SecTrustEvaluate] might look on the network for certificates in the certificate chain, |
||
1215 | * [it] might block while attempting network access. You should never call it from your main thread; |
||
1216 | * call it only from within a function running on a dispatch queue or on a separate thread. |
||
1217 | * |
||
1218 | * Thus this method uses a completionHandler block rather than a normal return value. |
||
1219 | * The completionHandler block is thread-safe, and may be invoked from a background queue/thread. |
||
1220 | * It is safe to invoke the completionHandler block even if the socket has been closed. |
||
1221 | **/ |
||
1222 | - (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust |
||
1223 | completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler; |
||
1224 | |||
1225 | @end |
||
1226 | NS_ASSUME_NONNULL_END |