Updated CocoaAsyncSocket. Added SO_REUSEPORT
This commit is contained in:
parent
cfcb081d61
commit
6f62be0d6e
|
@ -13,14 +13,14 @@
|
|||
#import <TargetConditionals.h>
|
||||
#import <Availability.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
extern NSString *const GCDAsyncUdpSocketException;
|
||||
extern NSString *const GCDAsyncUdpSocketErrorDomain;
|
||||
|
||||
extern NSString *const GCDAsyncUdpSocketQueueName;
|
||||
extern NSString *const GCDAsyncUdpSocketThreadName;
|
||||
|
||||
enum GCDAsyncUdpSocketError
|
||||
{
|
||||
typedef NS_ENUM(NSInteger, GCDAsyncUdpSocketError) {
|
||||
GCDAsyncUdpSocketNoError = 0, // Never used
|
||||
GCDAsyncUdpSocketBadConfigError, // Invalid configuration
|
||||
GCDAsyncUdpSocketBadParamError, // Invalid parameter was passed
|
||||
|
@ -28,7 +28,59 @@ enum GCDAsyncUdpSocketError
|
|||
GCDAsyncUdpSocketClosedError, // The socket was closed
|
||||
GCDAsyncUdpSocketOtherError, // Description provided in userInfo
|
||||
};
|
||||
typedef enum GCDAsyncUdpSocketError GCDAsyncUdpSocketError;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@class GCDAsyncUdpSocket;
|
||||
|
||||
@protocol GCDAsyncUdpSocketDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
* By design, UDP is a connectionless protocol, and connecting is not needed.
|
||||
* However, you may optionally choose to connect to a particular host for reasons
|
||||
* outlined in the documentation for the various connect methods listed above.
|
||||
*
|
||||
* This method is called if one of the connect methods are invoked, and the connection is successful.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address;
|
||||
|
||||
/**
|
||||
* By design, UDP is a connectionless protocol, and connecting is not needed.
|
||||
* However, you may optionally choose to connect to a particular host for reasons
|
||||
* outlined in the documentation for the various connect methods listed above.
|
||||
*
|
||||
* This method is called if one of the connect methods are invoked, and the connection fails.
|
||||
* This may happen, for example, if a domain name is given for the host and the domain name is unable to be resolved.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error;
|
||||
|
||||
/**
|
||||
* Called when the datagram with the given tag has been sent.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag;
|
||||
|
||||
/**
|
||||
* Called if an error occurs while trying to send a datagram.
|
||||
* This could be due to a timeout, or something more serious such as the data being too large to fit in a sigle packet.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error;
|
||||
|
||||
/**
|
||||
* Called when the socket has received the requested datagram.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
|
||||
fromAddress:(NSData *)address
|
||||
withFilterContext:(nullable id)filterContext;
|
||||
|
||||
/**
|
||||
* Called when the socket is closed.
|
||||
**/
|
||||
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError * _Nullable)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* You may optionally set a receive filter for the socket.
|
||||
|
@ -78,7 +130,7 @@ typedef enum GCDAsyncUdpSocketError GCDAsyncUdpSocketError;
|
|||
* [udpSocket setReceiveFilter:filter withQueue:myParsingQueue];
|
||||
*
|
||||
**/
|
||||
typedef BOOL (^GCDAsyncUdpSocketReceiveFilterBlock)(NSData *data, NSData *address, id *context);
|
||||
typedef BOOL (^GCDAsyncUdpSocketReceiveFilterBlock)(NSData *data, NSData *address, id __nullable * __nonnull context);
|
||||
|
||||
/**
|
||||
* You may optionally set a send filter for the socket.
|
||||
|
@ -126,24 +178,24 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
*
|
||||
* The delegate queue and socket queue can optionally be the same.
|
||||
**/
|
||||
- (id)init;
|
||||
- (id)initWithSocketQueue:(dispatch_queue_t)sq;
|
||||
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq;
|
||||
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq;
|
||||
- (instancetype)init;
|
||||
- (instancetype)initWithSocketQueue:(nullable dispatch_queue_t)sq;
|
||||
- (instancetype)initWithDelegate:(nullable id <GCDAsyncUdpSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq;
|
||||
- (instancetype)initWithDelegate:(nullable id <GCDAsyncUdpSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq;
|
||||
|
||||
#pragma mark Configuration
|
||||
|
||||
- (id)delegate;
|
||||
- (void)setDelegate:(id)delegate;
|
||||
- (void)synchronouslySetDelegate:(id)delegate;
|
||||
- (nullable id <GCDAsyncUdpSocketDelegate>)delegate;
|
||||
- (void)setDelegate:(nullable id <GCDAsyncUdpSocketDelegate>)delegate;
|
||||
- (void)synchronouslySetDelegate:(nullable id <GCDAsyncUdpSocketDelegate>)delegate;
|
||||
|
||||
- (dispatch_queue_t)delegateQueue;
|
||||
- (void)setDelegateQueue:(dispatch_queue_t)delegateQueue;
|
||||
- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)delegateQueue;
|
||||
- (nullable dispatch_queue_t)delegateQueue;
|
||||
- (void)setDelegateQueue:(nullable dispatch_queue_t)delegateQueue;
|
||||
- (void)synchronouslySetDelegateQueue:(nullable dispatch_queue_t)delegateQueue;
|
||||
|
||||
- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr;
|
||||
- (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
|
||||
- (void)synchronouslySetDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
|
||||
- (void)getDelegate:(id <GCDAsyncUdpSocketDelegate> __nullable * __nullable)delegatePtr delegateQueue:(dispatch_queue_t __nullable * __nullable)delegateQueuePtr;
|
||||
- (void)setDelegate:(nullable id <GCDAsyncUdpSocketDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;
|
||||
- (void)synchronouslySetDelegate:(nullable id <GCDAsyncUdpSocketDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;
|
||||
|
||||
/**
|
||||
* By default, both IPv4 and IPv6 are enabled.
|
||||
|
@ -179,7 +231,7 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
|
||||
/**
|
||||
* Gets/Sets the maximum size of the buffer that will be allocated for receive operations.
|
||||
* The default maximum size is 9216 bytes.
|
||||
* The default maximum size is 65535 bytes.
|
||||
*
|
||||
* The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535.
|
||||
* The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295.
|
||||
|
@ -199,12 +251,27 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
- (uint32_t)maxReceiveIPv6BufferSize;
|
||||
- (void)setMaxReceiveIPv6BufferSize:(uint32_t)max;
|
||||
|
||||
/**
|
||||
* Gets/Sets the maximum size of the buffer that will be allocated for send operations.
|
||||
* The default maximum size is 65535 bytes.
|
||||
*
|
||||
* Given that a typical link MTU is 1500 bytes, a large UDP datagram will have to be
|
||||
* fragmented, and that’s both expensive and risky (if one fragment goes missing, the
|
||||
* entire datagram is lost). You are much better off sending a large number of smaller
|
||||
* UDP datagrams, preferably using a path MTU algorithm to avoid fragmentation.
|
||||
*
|
||||
* You must set it before the sockt is created otherwise it won't work.
|
||||
*
|
||||
**/
|
||||
- (uint16_t)maxSendBufferSize;
|
||||
- (void)setMaxSendBufferSize:(uint16_t)max;
|
||||
|
||||
/**
|
||||
* User data allows you to associate arbitrary information with the socket.
|
||||
* This data is not used internally in any way.
|
||||
**/
|
||||
- (id)userData;
|
||||
- (void)setUserData:(id)arbitraryUserData;
|
||||
- (nullable id)userData;
|
||||
- (void)setUserData:(nullable id)arbitraryUserData;
|
||||
|
||||
#pragma mark Diagnostics
|
||||
|
||||
|
@ -217,16 +284,16 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* Note: Address info may not be available until after the socket has been binded, connected
|
||||
* or until after data has been sent.
|
||||
**/
|
||||
- (NSData *)localAddress;
|
||||
- (NSString *)localHost;
|
||||
- (nullable NSData *)localAddress;
|
||||
- (nullable NSString *)localHost;
|
||||
- (uint16_t)localPort;
|
||||
|
||||
- (NSData *)localAddress_IPv4;
|
||||
- (NSString *)localHost_IPv4;
|
||||
- (nullable NSData *)localAddress_IPv4;
|
||||
- (nullable NSString *)localHost_IPv4;
|
||||
- (uint16_t)localPort_IPv4;
|
||||
|
||||
- (NSData *)localAddress_IPv6;
|
||||
- (NSString *)localHost_IPv6;
|
||||
- (nullable NSData *)localAddress_IPv6;
|
||||
- (nullable NSString *)localHost_IPv6;
|
||||
- (uint16_t)localPort_IPv6;
|
||||
|
||||
/**
|
||||
|
@ -239,8 +306,8 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* will not be available unless the socket is explicitly connected to a remote host/port.
|
||||
* If the socket is not connected, these methods will return nil / 0.
|
||||
**/
|
||||
- (NSData *)connectedAddress;
|
||||
- (NSString *)connectedHost;
|
||||
- (nullable NSData *)connectedAddress;
|
||||
- (nullable NSString *)connectedHost;
|
||||
- (uint16_t)connectedPort;
|
||||
|
||||
/**
|
||||
|
@ -319,7 +386,7 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* On success, returns YES.
|
||||
* Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr.
|
||||
**/
|
||||
- (BOOL)bindToPort:(uint16_t)port interface:(NSString *)interface error:(NSError **)errPtr;
|
||||
- (BOOL)bindToPort:(uint16_t)port interface:(nullable NSString *)interface error:(NSError **)errPtr;
|
||||
|
||||
/**
|
||||
* Binds the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object.
|
||||
|
@ -418,10 +485,21 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* On success, returns YES.
|
||||
* Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
|
||||
**/
|
||||
- (BOOL)joinMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr;
|
||||
- (BOOL)joinMulticastGroup:(NSString *)group onInterface:(nullable NSString *)interface error:(NSError **)errPtr;
|
||||
|
||||
- (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr;
|
||||
- (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr;
|
||||
- (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(nullable NSString *)interface error:(NSError **)errPtr;
|
||||
|
||||
#pragma mark Reuse Port
|
||||
|
||||
/**
|
||||
* By default, only one socket can be bound to a given IP address + port at a time.
|
||||
* To enable multiple processes to simultaneously bind to the same address+port,
|
||||
* you need to enable this functionality in the socket. All processes that wish to
|
||||
* use the address+port simultaneously must all enable reuse port on the socket
|
||||
* bound to that port.
|
||||
**/
|
||||
- (BOOL)enableReusePort:(BOOL)flag error:(NSError **)errPtr;
|
||||
|
||||
#pragma mark Broadcast
|
||||
|
||||
|
@ -597,7 +675,7 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* Note: This method invokes setSendFilter:withQueue:isAsynchronous: (documented below),
|
||||
* passing YES for the isAsynchronous parameter.
|
||||
**/
|
||||
- (void)setSendFilter:(GCDAsyncUdpSocketSendFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue;
|
||||
- (void)setSendFilter:(nullable GCDAsyncUdpSocketSendFilterBlock)filterBlock withQueue:(nullable dispatch_queue_t)filterQueue;
|
||||
|
||||
/**
|
||||
* The receive filter can be run via dispatch_async or dispatch_sync.
|
||||
|
@ -612,8 +690,8 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* then you cannot perform any tasks which may invoke dispatch_sync on the socket queue.
|
||||
* For example, you can't query properties on the socket.
|
||||
**/
|
||||
- (void)setSendFilter:(GCDAsyncUdpSocketSendFilterBlock)filterBlock
|
||||
withQueue:(dispatch_queue_t)filterQueue
|
||||
- (void)setSendFilter:(nullable GCDAsyncUdpSocketSendFilterBlock)filterBlock
|
||||
withQueue:(nullable dispatch_queue_t)filterQueue
|
||||
isAsynchronous:(BOOL)isAsynchronous;
|
||||
|
||||
#pragma mark Receiving
|
||||
|
@ -729,7 +807,7 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* Note: This method invokes setReceiveFilter:withQueue:isAsynchronous: (documented below),
|
||||
* passing YES for the isAsynchronous parameter.
|
||||
**/
|
||||
- (void)setReceiveFilter:(GCDAsyncUdpSocketReceiveFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue;
|
||||
- (void)setReceiveFilter:(nullable GCDAsyncUdpSocketReceiveFilterBlock)filterBlock withQueue:(nullable dispatch_queue_t)filterQueue;
|
||||
|
||||
/**
|
||||
* The receive filter can be run via dispatch_async or dispatch_sync.
|
||||
|
@ -744,8 +822,8 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* then you cannot perform any tasks which may invoke dispatch_sync on the socket queue.
|
||||
* For example, you can't query properties on the socket.
|
||||
**/
|
||||
- (void)setReceiveFilter:(GCDAsyncUdpSocketReceiveFilterBlock)filterBlock
|
||||
withQueue:(dispatch_queue_t)filterQueue
|
||||
- (void)setReceiveFilter:(nullable GCDAsyncUdpSocketReceiveFilterBlock)filterBlock
|
||||
withQueue:(nullable dispatch_queue_t)filterQueue
|
||||
isAsynchronous:(BOOL)isAsynchronous;
|
||||
|
||||
#pragma mark Closing
|
||||
|
@ -897,8 +975,8 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* However, if you need one for any reason,
|
||||
* these methods are a convenient way to get access to a safe instance of one.
|
||||
**/
|
||||
- (CFReadStreamRef)readStream;
|
||||
- (CFWriteStreamRef)writeStream;
|
||||
- (nullable CFReadStreamRef)readStream;
|
||||
- (nullable CFWriteStreamRef)writeStream;
|
||||
|
||||
/**
|
||||
* This method is only available from within the context of a performBlock: invocation.
|
||||
|
@ -931,66 +1009,16 @@ typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address,
|
|||
* Extracting host/port/family information from raw address data.
|
||||
**/
|
||||
|
||||
+ (NSString *)hostFromAddress:(NSData *)address;
|
||||
+ (nullable NSString *)hostFromAddress:(NSData *)address;
|
||||
+ (uint16_t)portFromAddress:(NSData *)address;
|
||||
+ (int)familyFromAddress:(NSData *)address;
|
||||
|
||||
+ (BOOL)isIPv4Address:(NSData *)address;
|
||||
+ (BOOL)isIPv6Address:(NSData *)address;
|
||||
|
||||
+ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address;
|
||||
+ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(int *)afPtr fromAddress:(NSData *)address;
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@protocol GCDAsyncUdpSocketDelegate
|
||||
@optional
|
||||
|
||||
/**
|
||||
* By design, UDP is a connectionless protocol, and connecting is not needed.
|
||||
* However, you may optionally choose to connect to a particular host for reasons
|
||||
* outlined in the documentation for the various connect methods listed above.
|
||||
*
|
||||
* This method is called if one of the connect methods are invoked, and the connection is successful.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address;
|
||||
|
||||
/**
|
||||
* By design, UDP is a connectionless protocol, and connecting is not needed.
|
||||
* However, you may optionally choose to connect to a particular host for reasons
|
||||
* outlined in the documentation for the various connect methods listed above.
|
||||
*
|
||||
* This method is called if one of the connect methods are invoked, and the connection fails.
|
||||
* This may happen, for example, if a domain name is given for the host and the domain name is unable to be resolved.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error;
|
||||
|
||||
/**
|
||||
* Called when the datagram with the given tag has been sent.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag;
|
||||
|
||||
/**
|
||||
* Called if an error occurs while trying to send a datagram.
|
||||
* This could be due to a timeout, or something more serious such as the data being too large to fit in a sigle packet.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error;
|
||||
|
||||
/**
|
||||
* Called when the socket has received the requested datagram.
|
||||
**/
|
||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
|
||||
fromAddress:(NSData *)address
|
||||
withFilterContext:(id)filterContext;
|
||||
|
||||
/**
|
||||
* Called when the socket is closed.
|
||||
**/
|
||||
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError *)error;
|
||||
+ (BOOL)getHost:(NSString * __nullable * __nullable)hostPtr port:(uint16_t * __nullable)portPtr fromAddress:(NSData *)address;
|
||||
+ (BOOL)getHost:(NSString * __nullable * __nullable)hostPtr port:(uint16_t * __nullable)portPtr family:(int * __nullable)afPtr fromAddress:(NSData *)address;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -167,6 +167,8 @@ enum GCDAsyncUdpSocketConfig
|
|||
uint16_t max4ReceiveSize;
|
||||
uint32_t max6ReceiveSize;
|
||||
|
||||
uint16_t maxSendSize;
|
||||
|
||||
int socket4FD;
|
||||
int socket6FD;
|
||||
|
||||
|
@ -350,14 +352,14 @@ enum GCDAsyncUdpSocketConfig
|
|||
return [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq];
|
||||
}
|
||||
|
||||
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq
|
||||
- (id)initWithDelegate:(id <GCDAsyncUdpSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq
|
||||
{
|
||||
LogTrace();
|
||||
|
||||
return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL];
|
||||
}
|
||||
|
||||
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
|
||||
- (id)initWithDelegate:(id <GCDAsyncUdpSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
|
||||
{
|
||||
LogTrace();
|
||||
|
||||
|
@ -373,8 +375,10 @@ enum GCDAsyncUdpSocketConfig
|
|||
#endif
|
||||
}
|
||||
|
||||
max4ReceiveSize = 9216;
|
||||
max6ReceiveSize = 9216;
|
||||
max4ReceiveSize = 65535;
|
||||
max6ReceiveSize = 65535;
|
||||
|
||||
maxSendSize = 65535;
|
||||
|
||||
socket4FD = SOCKET_NULL;
|
||||
socket6FD = SOCKET_NULL;
|
||||
|
@ -488,7 +492,7 @@ enum GCDAsyncUdpSocketConfig
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously
|
||||
- (void)setDelegate:(id <GCDAsyncUdpSocketDelegate>)newDelegate synchronously:(BOOL)synchronously
|
||||
{
|
||||
dispatch_block_t block = ^{
|
||||
delegate = newDelegate;
|
||||
|
@ -505,12 +509,12 @@ enum GCDAsyncUdpSocketConfig
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)newDelegate
|
||||
- (void)setDelegate:(id <GCDAsyncUdpSocketDelegate>)newDelegate
|
||||
{
|
||||
[self setDelegate:newDelegate synchronously:NO];
|
||||
}
|
||||
|
||||
- (void)synchronouslySetDelegate:(id)newDelegate
|
||||
- (void)synchronouslySetDelegate:(id <GCDAsyncUdpSocketDelegate>)newDelegate
|
||||
{
|
||||
[self setDelegate:newDelegate synchronously:YES];
|
||||
}
|
||||
|
@ -566,7 +570,7 @@ enum GCDAsyncUdpSocketConfig
|
|||
[self setDelegateQueue:newDelegateQueue synchronously:YES];
|
||||
}
|
||||
|
||||
- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
|
||||
- (void)getDelegate:(id <GCDAsyncUdpSocketDelegate> *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
|
||||
{
|
||||
if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
|
||||
{
|
||||
|
@ -588,7 +592,7 @@ enum GCDAsyncUdpSocketConfig
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
|
||||
- (void)setDelegate:(id <GCDAsyncUdpSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
|
||||
{
|
||||
dispatch_block_t block = ^{
|
||||
|
||||
|
@ -613,12 +617,12 @@ enum GCDAsyncUdpSocketConfig
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
|
||||
- (void)setDelegate:(id <GCDAsyncUdpSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
|
||||
{
|
||||
[self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO];
|
||||
}
|
||||
|
||||
- (void)synchronouslySetDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
|
||||
- (void)synchronouslySetDelegate:(id <GCDAsyncUdpSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
|
||||
{
|
||||
[self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES];
|
||||
}
|
||||
|
@ -864,6 +868,37 @@ enum GCDAsyncUdpSocketConfig
|
|||
dispatch_async(socketQueue, block);
|
||||
}
|
||||
|
||||
- (void)setMaxSendBufferSize:(uint16_t)max
|
||||
{
|
||||
dispatch_block_t block = ^{
|
||||
|
||||
LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max);
|
||||
|
||||
maxSendSize = max;
|
||||
};
|
||||
|
||||
if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
|
||||
block();
|
||||
else
|
||||
dispatch_async(socketQueue, block);
|
||||
}
|
||||
|
||||
- (uint16_t)maxSendBufferSize
|
||||
{
|
||||
__block uint16_t result = 0;
|
||||
|
||||
dispatch_block_t block = ^{
|
||||
|
||||
result = maxSendSize;
|
||||
};
|
||||
|
||||
if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
|
||||
block();
|
||||
else
|
||||
dispatch_sync(socketQueue, block);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (id)userData
|
||||
{
|
||||
|
@ -906,9 +941,9 @@ enum GCDAsyncUdpSocketConfig
|
|||
{
|
||||
LogTrace();
|
||||
|
||||
if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didConnectToAddress:)])
|
||||
__strong id theDelegate = delegate;
|
||||
if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didConnectToAddress:)])
|
||||
{
|
||||
id theDelegate = delegate;
|
||||
NSData *address = [anAddress copy]; // In case param is NSMutableData
|
||||
|
||||
dispatch_async(delegateQueue, ^{ @autoreleasepool {
|
||||
|
@ -922,10 +957,9 @@ enum GCDAsyncUdpSocketConfig
|
|||
{
|
||||
LogTrace();
|
||||
|
||||
if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didNotConnect:)])
|
||||
__strong id theDelegate = delegate;
|
||||
if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didNotConnect:)])
|
||||
{
|
||||
id theDelegate = delegate;
|
||||
|
||||
dispatch_async(delegateQueue, ^{ @autoreleasepool {
|
||||
|
||||
[theDelegate udpSocket:self didNotConnect:error];
|
||||
|
@ -937,10 +971,9 @@ enum GCDAsyncUdpSocketConfig
|
|||
{
|
||||
LogTrace();
|
||||
|
||||
if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didSendDataWithTag:)])
|
||||
__strong id theDelegate = delegate;
|
||||
if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didSendDataWithTag:)])
|
||||
{
|
||||
id theDelegate = delegate;
|
||||
|
||||
dispatch_async(delegateQueue, ^{ @autoreleasepool {
|
||||
|
||||
[theDelegate udpSocket:self didSendDataWithTag:tag];
|
||||
|
@ -952,10 +985,9 @@ enum GCDAsyncUdpSocketConfig
|
|||
{
|
||||
LogTrace();
|
||||
|
||||
if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didNotSendDataWithTag:dueToError:)])
|
||||
__strong id theDelegate = delegate;
|
||||
if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didNotSendDataWithTag:dueToError:)])
|
||||
{
|
||||
id theDelegate = delegate;
|
||||
|
||||
dispatch_async(delegateQueue, ^{ @autoreleasepool {
|
||||
|
||||
[theDelegate udpSocket:self didNotSendDataWithTag:tag dueToError:error];
|
||||
|
@ -969,10 +1001,9 @@ enum GCDAsyncUdpSocketConfig
|
|||
|
||||
SEL selector = @selector(udpSocket:didReceiveData:fromAddress:withFilterContext:);
|
||||
|
||||
if (delegateQueue && [delegate respondsToSelector:selector])
|
||||
__strong id theDelegate = delegate;
|
||||
if (delegateQueue && [theDelegate respondsToSelector:selector])
|
||||
{
|
||||
id theDelegate = delegate;
|
||||
|
||||
dispatch_async(delegateQueue, ^{ @autoreleasepool {
|
||||
|
||||
[theDelegate udpSocket:self didReceiveData:data fromAddress:address withFilterContext:context];
|
||||
|
@ -984,10 +1015,9 @@ enum GCDAsyncUdpSocketConfig
|
|||
{
|
||||
LogTrace();
|
||||
|
||||
if (delegateQueue && [delegate respondsToSelector:@selector(udpSocketDidClose:withError:)])
|
||||
__strong id theDelegate = delegate;
|
||||
if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocketDidClose:withError:)])
|
||||
{
|
||||
id theDelegate = delegate;
|
||||
|
||||
dispatch_async(delegateQueue, ^{ @autoreleasepool {
|
||||
|
||||
[theDelegate udpSocketDidClose:self withError:error];
|
||||
|
@ -1204,9 +1234,17 @@ enum GCDAsyncUdpSocketConfig
|
|||
}
|
||||
else if (res->ai_family == AF_INET6)
|
||||
{
|
||||
// Found IPv6 address
|
||||
// Wrap the native address structure and add to list
|
||||
|
||||
// Fixes connection issues with IPv6, it is the same solution for udp socket.
|
||||
// https://github.com/robbiehanson/CocoaAsyncSocket/issues/429#issuecomment-222477158
|
||||
struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)res->ai_addr;
|
||||
in_port_t *portPtr = &sockaddr->sin6_port;
|
||||
if ((portPtr != NULL) && (*portPtr == 0)) {
|
||||
*portPtr = htons(port);
|
||||
}
|
||||
|
||||
// Found IPv6 address
|
||||
// Wrap the native address structure and add to list
|
||||
[addresses addObject:[NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]];
|
||||
}
|
||||
}
|
||||
|
@ -1983,6 +2021,39 @@ enum GCDAsyncUdpSocketConfig
|
|||
return SOCKET_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535.
|
||||
* The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295.
|
||||
*
|
||||
* The default maximum size of the UDP buffer in iOS is 9216 bytes.
|
||||
*
|
||||
* This is the reason of #222(GCD does not necessarily return the size of an entire UDP packet) and
|
||||
* #535(GCDAsyncUDPSocket can not send data when data is greater than 9K)
|
||||
*
|
||||
*
|
||||
* Enlarge the maximum size of UDP packet.
|
||||
* I can not ensure the protocol type now so that the max size is set to 65535 :)
|
||||
**/
|
||||
|
||||
status = setsockopt(socketFD, SOL_SOCKET, SO_SNDBUF, (const char*)&maxSendSize, sizeof(int));
|
||||
if (status == -1)
|
||||
{
|
||||
if (errPtr)
|
||||
*errPtr = [self errnoErrorWithReason:@"Error setting send buffer size (setsockopt)"];
|
||||
close(socketFD);
|
||||
return SOCKET_NULL;
|
||||
}
|
||||
|
||||
status = setsockopt(socketFD, SOL_SOCKET, SO_RCVBUF, (const char*)&maxSendSize, sizeof(int));
|
||||
if (status == -1)
|
||||
{
|
||||
if (errPtr)
|
||||
*errPtr = [self errnoErrorWithReason:@"Error setting receive buffer size (setsockopt)"];
|
||||
close(socketFD);
|
||||
return SOCKET_NULL;
|
||||
}
|
||||
|
||||
|
||||
return socketFD;
|
||||
};
|
||||
|
||||
|
@ -3453,6 +3524,70 @@ enum GCDAsyncUdpSocketConfig
|
|||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Reuse port
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (BOOL)enableReusePort:(BOOL)flag error:(NSError **)errPtr
|
||||
{
|
||||
__block BOOL result = NO;
|
||||
__block NSError *err = nil;
|
||||
|
||||
dispatch_block_t block = ^{ @autoreleasepool {
|
||||
|
||||
if (![self preOp:&err])
|
||||
{
|
||||
return_from_block;
|
||||
}
|
||||
|
||||
if ((flags & kDidCreateSockets) == 0)
|
||||
{
|
||||
if (![self createSockets:&err])
|
||||
{
|
||||
return_from_block;
|
||||
}
|
||||
}
|
||||
|
||||
int value = flag ? 1 : 0;
|
||||
if (socket4FD != SOCKET_NULL)
|
||||
{
|
||||
int error = setsockopt(socket4FD, SOL_SOCKET, SO_REUSEPORT, (const void *)&value, sizeof(value));
|
||||
|
||||
if (error)
|
||||
{
|
||||
err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
|
||||
|
||||
return_from_block;
|
||||
}
|
||||
result = YES;
|
||||
}
|
||||
|
||||
if (socket6FD != SOCKET_NULL)
|
||||
{
|
||||
int error = setsockopt(socket6FD, SOL_SOCKET, SO_REUSEPORT, (const void *)&value, sizeof(value));
|
||||
|
||||
if (error)
|
||||
{
|
||||
err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
|
||||
|
||||
return_from_block;
|
||||
}
|
||||
result = YES;
|
||||
}
|
||||
|
||||
}};
|
||||
|
||||
if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
|
||||
block();
|
||||
else
|
||||
dispatch_sync(socketQueue, block);
|
||||
|
||||
if (errPtr)
|
||||
*errPtr = err;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Broadcast
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -3526,6 +3661,8 @@ enum GCDAsyncUdpSocketConfig
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GCDAsyncUdpSendPacket *packet = [[GCDAsyncUdpSendPacket alloc] initWithData:data timeout:timeout tag:tag];
|
||||
|
||||
dispatch_async(socketQueue, ^{ @autoreleasepool {
|
||||
|
@ -4293,7 +4430,9 @@ enum GCDAsyncUdpSocketConfig
|
|||
struct sockaddr_in sockaddr4;
|
||||
socklen_t sockaddr4len = sizeof(sockaddr4);
|
||||
|
||||
size_t bufSize = MIN(max4ReceiveSize, socket4FDBytesAvailable);
|
||||
// #222: GCD does not necessarily return the size of an entire UDP packet
|
||||
// from dispatch_source_get_data(), so we must use the maximum packet size.
|
||||
size_t bufSize = max4ReceiveSize;
|
||||
void *buf = malloc(bufSize);
|
||||
|
||||
result = recvfrom(socket4FD, buf, bufSize, 0, (struct sockaddr *)&sockaddr4, &sockaddr4len);
|
||||
|
@ -4328,7 +4467,9 @@ enum GCDAsyncUdpSocketConfig
|
|||
struct sockaddr_in6 sockaddr6;
|
||||
socklen_t sockaddr6len = sizeof(sockaddr6);
|
||||
|
||||
size_t bufSize = MIN(max6ReceiveSize, socket6FDBytesAvailable);
|
||||
// #222: GCD does not necessarily return the size of an entire UDP packet
|
||||
// from dispatch_source_get_data(), so we must use the maximum packet size.
|
||||
size_t bufSize = max6ReceiveSize;
|
||||
void *buf = malloc(bufSize);
|
||||
|
||||
result = recvfrom(socket6FD, buf, bufSize, 0, (struct sockaddr *)&sockaddr6, &sockaddr6len);
|
||||
|
|
|
@ -96,6 +96,7 @@ NSString *const RCTUDPErrorDomain = @"RCTUDPErrorDomain";
|
|||
|
||||
[_udpSocket setMaxReceiveIPv4BufferSize:UINT16_MAX];
|
||||
[_udpSocket setMaxReceiveIPv6BufferSize:UINT16_MAX];
|
||||
[_udpSocket enableReusePort:true error:error];
|
||||
|
||||
BOOL result;
|
||||
if (address) {
|
||||
|
|
Loading…
Reference in New Issue