FWAsyncUdpSocket

@class FWAsyncUdpSocket;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    • FWAsyncUdpSocket uses the standard delegate paradigm,
    • but executes all delegate callbacks on a given delegate dispatch queue.
    • This allows for maximum concurrency, while at the same time providing easy thread safety.
    • You MUST set a delegate AND delegate dispatch queue before attempting to
    • use the socket, or you will get an error.
    • The socket queue is optional.
    • If you pass NULL, FWAsyncSocket will automatically create its own socket queue.
    • If you choose to provide a socket queue, the socket queue must not be a concurrent queue,
    • then please see the discussion for the method markSocketQueueTargetQueue. *
    • The delegate queue and socket queue can optionally be the same.

    Declaration

    Objective-C

    - (nonnull instancetype)init;
  • Undocumented

    Declaration

    Objective-C

    - (instancetype)initWithSocketQueue:(nullable dispatch_queue_t)sq;
  • Undocumented

    Declaration

    Objective-C

    - (instancetype)initWithDelegate:(nullable id<FWAsyncUdpSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq;
  • Undocumented

    Declaration

    Objective-C

    - (instancetype)initWithDelegate:(nullable id<FWAsyncUdpSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq NS_DESIGNATED_INITIALIZER;

Configuration

  • Undocumented

    Declaration

    Objective-C

    - (nullable id<FWAsyncUdpSocketDelegate>)delegate;
  • Undocumented

    Declaration

    Objective-C

    - (void)setDelegate:(nullable id<FWAsyncUdpSocketDelegate>)delegate;
  • Undocumented

    Declaration

    Objective-C

    - (void)synchronouslySetDelegate:(nullable id<FWAsyncUdpSocketDelegate>)delegate;
  • Undocumented

    Declaration

    Objective-C

    - (nullable dispatch_queue_t)delegateQueue;
  • Undocumented

    Declaration

    Objective-C

    - (void)setDelegateQueue:(nullable dispatch_queue_t)delegateQueue;
  • Undocumented

    Declaration

    Objective-C

    - (void)synchronouslySetDelegateQueue:(nullable dispatch_queue_t)delegateQueue;
  • Undocumented

    Declaration

    Objective-C

    - (void)getDelegate:(id<FWAsyncUdpSocketDelegate> __nullable * __nullable)delegatePtr delegateQueue:(dispatch_queue_t __nullable * __nullable)delegateQueuePtr;
  • Undocumented

    Declaration

    Objective-C

    - (void)setDelegate:(nullable id<FWAsyncUdpSocketDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;
  • Undocumented

    Declaration

    Objective-C

    - (void)synchronouslySetDelegate:(nullable id<FWAsyncUdpSocketDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;
  • By default, both IPv4 and IPv6 are enabled.

    This means FWAsyncUdpSocket automatically supports both protocols, and can send to IPv4 or IPv6 addresses, as well as receive over IPv4 and IPv6.

    For operations that require DNS resolution, FWAsyncUdpSocket supports both IPv4 and IPv6. If a DNS lookup returns only IPv4 results, FWAsyncUdpSocket will automatically use IPv4. If a DNS lookup returns only IPv6 results, FWAsyncUdpSocket will automatically use IPv6. If a DNS lookup returns both IPv4 and IPv6 results, then the protocol used depends on the configured preference. If IPv4 is preferred, then IPv4 is used. If IPv6 is preferred, then IPv6 is used. If neutral, then the first IP version in the resolved array will be used.

    Starting with Mac OS X 10.7 Lion and iOS 5, the default IP preference is neutral. On prior systems the default IP preference is IPv4.

    Declaration

    Objective-C

    - (BOOL)isIPv4Enabled;
  • Undocumented

    Declaration

    Objective-C

    - (void)setIPv4Enabled:(BOOL)flag;
  • Undocumented

    Declaration

    Objective-C

    - (BOOL)isIPv6Enabled;
  • Undocumented

    Declaration

    Objective-C

    - (void)setIPv6Enabled:(BOOL)flag;
  • Undocumented

    Declaration

    Objective-C

    - (BOOL)isIPv4Preferred;
  • Undocumented

    Declaration

    Objective-C

    - (BOOL)isIPv6Preferred;
  • Undocumented

    Declaration

    Objective-C

    - (BOOL)isIPVersionNeutral;
  • Undocumented

    Declaration

    Objective-C

    - (void)setPreferIPv4;
  • Undocumented

    Declaration

    Objective-C

    - (void)setPreferIPv6;
  • Undocumented

    Declaration

    Objective-C

    - (void)setIPVersionNeutral;
    • Gets/Sets the maximum size of the buffer that will be allocated for receive operations.
    • 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.

    Since

    Since the OS/FW notifies us of the size of each received UDP packet,
    • the actual allocated buffer size for each packet is exact.
    • And in practice the size of UDP packets is generally much smaller than the max.
    • Indeed most protocols will send and receive packets of only a few bytes,
    • or will set a limit on the size of packets to prevent fragmentation in the IP layer.
    • If you set the buffer size too small, the sockets API in the OS will silently discard
    • any extra data, and you will not be notified of the error.

    Declaration

    Objective-C

    - (uint16_t)maxReceiveIPv4BufferSize;
  • Undocumented

    Declaration

    Objective-C

    - (void)setMaxReceiveIPv4BufferSize:(uint16_t)max;
  • Undocumented

    Declaration

    Objective-C

    - (uint32_t)maxReceiveIPv6BufferSize;
  • Undocumented

    Declaration

    Objective-C

    - (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.

    Declaration

    Objective-C

    - (uint16_t)maxSendBufferSize;
  • Undocumented

    Declaration

    Objective-C

    - (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.

    Declaration

    Objective-C

    - (nullable id)userData;
  • Undocumented

    Declaration

    Objective-C

    - (void)setUserData:(nullable id)arbitraryUserData;

Diagnostics

    • The localAddress method returns a sockaddr structure wrapped in a NSData object.
    • The localHost method returns the human readable IP address as a string.

    Note

    Address info may not be available until after the socket has been binded, connected
    • or until after data has been sent.

    Declaration

    Objective-C

    - (nullable NSData *)localAddress;
  • Undocumented

    Declaration

    Objective-C

    - (nullable NSString *)localHost;
  • Undocumented

    Declaration

    Objective-C

    - (uint16_t)localPort;
  • Undocumented

    Declaration

    Objective-C

    - (nullable NSData *)localAddress_IPv4;
  • Undocumented

    Declaration

    Objective-C

    - (nullable NSString *)localHost_IPv4;
  • Undocumented

    Declaration

    Objective-C

    - (uint16_t)localPort_IPv4;
  • Undocumented

    Declaration

    Objective-C

    - (nullable NSData *)localAddress_IPv6;
  • Undocumented

    Declaration

    Objective-C

    - (nullable NSString *)localHost_IPv6;
  • Undocumented

    Declaration

    Objective-C

    - (uint16_t)localPort_IPv6;
    • The connectedAddress method returns a sockaddr structure wrapped in a NSData object.
    • The connectedHost method returns the human readable IP address as a string.

    Note

    Since UDP is connectionless by design, connected address info
    • 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.

    Declaration

    Objective-C

    - (nullable NSData *)connectedAddress;
  • Undocumented

    Declaration

    Objective-C

    - (nullable NSString *)connectedHost;
  • Undocumented

    Declaration

    Objective-C

    - (uint16_t)connectedPort;
    • By design, UDP is a connectionless protocol, and connecting is not needed.
    • If connected, the socket will only be able to send/receive data to/from the connected host.

    Declaration

    Objective-C

    - (BOOL)isConnected;
    • The only way a socket can be closed is if you explicitly call one of the close methods.

    Declaration

    Objective-C

    - (BOOL)isClosed;
    • By default this will be true, unless:
    • - IPv4 is disabled (via setIPv4Enabled:)
    • - The socket is explicitly bound to an IPv6 address
    • - The socket is connected to an IPv6 address

    Declaration

    Objective-C

    - (BOOL)isIPv4;
    • By default this will be true, unless:
    • - IPv6 is disabled (via setIPv6Enabled:)
    • - The socket is explicitly bound to an IPv4 address
    • _ The socket is connected to an IPv4 address
    • This method will also return false on platforms that do not support IPv6.

    Note

    The iPhone does not currently support IPv6.

    Declaration

    Objective-C

    - (BOOL)isIPv6;

Binding

    • Binds the UDP socket to the given port.
    • Binding should be done for server sockets that receive data prior to sending it.
    • Client sockets can skip binding,
    • as the OS will automatically assign the socket an available port when it starts sending data.
    • You may optionally pass a port number of zero to immediately bind the socket,
    • yet still allow the OS to automatically assign an available port.
    • You cannot bind a socket after its been connected.
    • You can only bind a socket once.
    • You can still connect a socket (if desired) after binding.
    • On success, returns YES.
    • Otherwise returns NO, and sets errPtr. If you don’t care about the error, you can pass NULL for errPtr.

    Declaration

    Objective-C

    - (BOOL)bindToPort:(uint16_t)port
                 error:(NSError *__autoreleasing _Nullable *_Nullable)errPtr;
    • Binds the UDP socket to the given port and optional interface.
    • Binding should be done for server sockets that receive data prior to sending it.
    • Client sockets can skip binding,
    • as the OS will automatically assign the socket an available port when it starts sending data.
    • You may optionally pass a port number of zero to immediately bind the socket,
    • yet still allow the OS to automatically assign an available port.
    • The interface may be a name (e.g. “en1” or “lo0”) or the corresponding IP address (e.g. “192.168.4.35”).
    • You may also use the special strings “localhost” or “loopback” to specify that
    • the socket only accept packets from the local machine.
    • You cannot bind a socket after its been connected.
    • You can only bind a socket once.
    • You can still connect a socket (if desired) after binding.
    • On success, returns YES.
    • Otherwise returns NO, and sets errPtr. If you don’t care about the error, you can pass NULL for errPtr.

    Declaration

    Objective-C

    - (BOOL)bindToPort:(uint16_t)port interface:(nullable NSString *)interface error:(NSError *__autoreleasing  _Nullable * _Nullable)errPtr;
    • Binds the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object.
    • If you have an existing struct sockaddr you can convert it to a NSData object like so:
    • struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
    • struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
    • Binding should be done for server sockets that receive data prior to sending it.
    • Client sockets can skip binding,
    • as the OS will automatically assign the socket an available port when it starts sending data.
    • You cannot bind a socket after its been connected.
    • You can only bind a socket once.
    • You can still connect a socket (if desired) after binding.
    • On success, returns YES.
    • Otherwise returns NO, and sets errPtr. If you don’t care about the error, you can pass NULL for errPtr.

    Declaration

    Objective-C

    - (BOOL)bindToAddress:(nonnull NSData *)localAddr
                    error:(NSError *__autoreleasing _Nullable *_Nullable)errPtr;

Connecting

  • Connects the UDP socket to the given host and port. By design, UDP is a connectionless protocol, and connecting is not needed.

    Choosing to connect to a specific host/port has the following effect:

    • You will only be able to send data to the connected host/port.
    • You will only be able to receive data from the connected host/port.
    • You will receive ICMP messages that come from the connected host/port, such as “connection refused”.

    The actual process of connecting a UDP socket does not result in any communication on the socket. It simply changes the internal state of the socket.

    You cannot bind a socket after it has been connected. You can only connect a socket once.

    The host may be a domain name (e.g. “deusty.com”) or an IP address string (e.g. “192.168.0.2”).

    This method is asynchronous as it requires a DNS lookup to resolve the given host name. If an obvious error is detected, this method immediately returns NO and sets errPtr. If you don’t care about the error, you can pass nil for errPtr. Otherwise, this method returns YES and begins the asynchronous connection process. The result of the asynchronous connection process will be reported via the delegate methods.

    Declaration

    Objective-C

    - (BOOL)connectToHost:(nonnull NSString *)host
                   onPort:(uint16_t)port
                    error:(NSError *__autoreleasing _Nullable *_Nullable)errPtr;
    • Connects the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object.
    • If you have an existing struct sockaddr you can convert it to a NSData object like so:
    • struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
    • struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
    • By design, UDP is a connectionless protocol, and connecting is not needed.
    • Choosing to connect to a specific address has the following effect:
    • - You will only be able to send data to the connected address.
    • - You will only be able to receive data from the connected address.
    • - You will receive ICMP messages that come from the connected address, such as “connection refused”.
    • Connecting a UDP socket does not result in any communication on the socket.
    • It simply changes the internal state of the socket.
    • You cannot bind a socket after its been connected.
    • You can only connect a socket once.
    • On success, returns YES.
    • Otherwise returns NO, and sets errPtr. If you don’t care about the error, you can pass nil for errPtr.

    Note

    Unlike the connectToHost:onPort:error: method, this method does not require a DNS lookup.
    • Thus when this method returns, the connection has either failed or fully completed.
    • In other words, this method is synchronous, unlike the asynchronous connectToHost::: method.
    • However, for compatibility and simplification of delegate code, if this method returns YES
    • then the corresponding delegate method (udpSocket:didConnectToHost:port:) is still invoked.

    Declaration

    Objective-C

    - (BOOL)connectToAddress:(nonnull NSData *)remoteAddr
                       error:(NSError *__autoreleasing _Nullable *_Nullable)errPtr;

Multicast

    • Join multicast group.
    • Group should be an IP address (eg @“225.228.0.1”).
    • On success, returns YES.
    • Otherwise returns NO, and sets errPtr. If you don’t care about the error, you can pass nil for errPtr.

    Declaration

    Objective-C

    - (BOOL)joinMulticastGroup:(nonnull NSString *)group
                         error:
                             (NSError *__autoreleasing _Nullable *_Nullable)errPtr;
    • Join multicast group.
    • Group should be an IP address (eg @“225.228.0.1”).
    • The interface may be a name (e.g. “en1” or “lo0”) or the corresponding IP address (e.g. “192.168.4.35”).
    • On success, returns YES.
    • Otherwise returns NO, and sets errPtr. If you don’t care about the error, you can pass nil for errPtr.

    Declaration

    Objective-C

    - (BOOL)joinMulticastGroup:(nonnull NSString *)group onInterface:(nullable NSString *)interface error:(NSError *__autoreleasing  _Nullable * _Nullable)errPtr;
  • Undocumented

    Declaration

    Objective-C

    - (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr;
  • Undocumented

    Declaration

    Objective-C

    - (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(nullable NSString *)interface error:(NSError **)errPtr;

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.

    Declaration

    Objective-C

    - (BOOL)enableReusePort:(BOOL)flag
                      error:(NSError *__autoreleasing _Nullable *_Nullable)errPtr;

Broadcast

    • By default, the underlying socket in the OS will not allow you to send broadcast messages.
    • In order to send broadcast messages, you need to enable this functionality in the socket.
    • A broadcast is a UDP message to addresses like “192.168.255.255” or “255.255.255.255” that is
    • delivered to every host on the network.
    • The reason this is generally disabled by default (by the OS) is to prevent
    • accidental broadcast messages from flooding the network.

    Declaration

    Objective-C

    - (BOOL)enableBroadcast:(BOOL)flag
                      error:(NSError *__autoreleasing _Nullable *_Nullable)errPtr;

Sending

    • Asynchronously sends the given data, with the given timeout and tag.
    • This method may only be used with a connected socket.
    • Recall that connecting is optional for a UDP socket.
    • For connected sockets, data can only be sent to the connected address.
    • For non-connected sockets, the remote destination is specified for each packet.
    • For more information about optionally connecting udp sockets, see the documentation for the connect methods above.
    • - parameter: data
    • The data to send.
    • If data is nil or zero-length, this method does nothing.
    • If passing NSMutableData, please read the thread-safety notice below.
    • - parameter: timeout
    • The timeout for the send opeartion.
    • If the timeout value is negative, the send operation will not use a timeout.
    • - parameter: tag
    • The tag is for your convenience.
    • It is not sent or received over the socket in any manner what-so-ever.
    • It is reported back as a parameter in the udpSocket:didSendDataWithTag:
    • or udpSocket:didNotSendDataWithTag:dueToError: methods.
    • You can use it as an array index, state id, type constant, etc.
    • Thread-Safety Note:
    • If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while
    • the socket is sending it. In other words, it’s not safe to alter the data until after the delegate method
    • udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying
    • that this particular send operation has completed.
    • This is due to the fact that FWAsyncUdpSocket does NOT copy the data.
    • It simply retains it for performance reasons.
    • Often times, if NSMutableData is passed, it is because a request/response was built up in memory.
    • Copying this data adds an unwanted/unneeded overhead.
    • If you need to write data from an immutable buffer, and you need to alter the buffer before the socket
    • completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time
    • when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method.

    Declaration

    Objective-C

    - (void)sendData:(nonnull NSData *)data
         withTimeout:(NSTimeInterval)timeout
                 tag:(long)tag;
    • Asynchronously sends the given data, with the given timeout and tag, to the given host and port.
    • This method cannot be used with a connected socket.
    • Recall that connecting is optional for a UDP socket.
    • For connected sockets, data can only be sent to the connected address.
    • For non-connected sockets, the remote destination is specified for each packet.
    • For more information about optionally connecting udp sockets, see the documentation for the connect methods above.
    • - parameter: data
    • The data to send.
    • If data is nil or zero-length, this method does nothing.
    • If passing NSMutableData, please read the thread-safety notice below.
    • - parameter: host
    • The destination to send the udp packet to.
    • May be specified as a domain name (e.g. “deusty.com”) or an IP address string (e.g. “192.168.0.2”).
    • You may also use the convenience strings of “loopback” or “localhost”.
    • - parameter: port
    • The port of the host to send to.
    • - parameter: timeout
    • The timeout for the send opeartion.
    • If the timeout value is negative, the send operation will not use a timeout.
    • - parameter: tag
    • The tag is for your convenience.
    • It is not sent or received over the socket in any manner what-so-ever.
    • It is reported back as a parameter in the udpSocket:didSendDataWithTag:
    • or udpSocket:didNotSendDataWithTag:dueToError: methods.
    • You can use it as an array index, state id, type constant, etc.
    • Thread-Safety Note:
    • If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while
    • the socket is sending it. In other words, it’s not safe to alter the data until after the delegate method
    • udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying
    • that this particular send operation has completed.
    • This is due to the fact that FWAsyncUdpSocket does NOT copy the data.
    • It simply retains it for performance reasons.
    • Often times, if NSMutableData is passed, it is because a request/response was built up in memory.
    • Copying this data adds an unwanted/unneeded overhead.
    • If you need to write data from an immutable buffer, and you need to alter the buffer before the socket
    • completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time
    • when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method.

    Declaration

    Objective-C

    - (void)sendData:(nonnull NSData *)data
              toHost:(nonnull NSString *)host
                port:(uint16_t)port
         withTimeout:(NSTimeInterval)timeout
                 tag:(long)tag;
    • Asynchronously sends the given data, with the given timeout and tag, to the given address.
    • This method cannot be used with a connected socket.
    • Recall that connecting is optional for a UDP socket.
    • For connected sockets, data can only be sent to the connected address.
    • For non-connected sockets, the remote destination is specified for each packet.
    • For more information about optionally connecting udp sockets, see the documentation for the connect methods above.
    • - parameter: data
    • The data to send.
    • If data is nil or zero-length, this method does nothing.
    • If passing NSMutableData, please read the thread-safety notice below.
    • - parameter: remoteAddr
    • The address to send the data to (specified as a sockaddr structure wrapped in a NSData object).
    • - parameter: timeout
    • The timeout for the send opeartion.
    • If the timeout value is negative, the send operation will not use a timeout.
    • - parameter: tag
    • The tag is for your convenience.
    • It is not sent or received over the socket in any manner what-so-ever.
    • It is reported back as a parameter in the udpSocket:didSendDataWithTag:
    • or udpSocket:didNotSendDataWithTag:dueToError: methods.
    • You can use it as an array index, state id, type constant, etc.
    • Thread-Safety Note:
    • If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while
    • the socket is sending it. In other words, it’s not safe to alter the data until after the delegate method
    • udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying
    • that this particular send operation has completed.
    • This is due to the fact that FWAsyncUdpSocket does NOT copy the data.
    • It simply retains it for performance reasons.
    • Often times, if NSMutableData is passed, it is because a request/response was built up in memory.
    • Copying this data adds an unwanted/unneeded overhead.
    • If you need to write data from an immutable buffer, and you need to alter the buffer before the socket
    • completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time
    • when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method.

    Declaration

    Objective-C

    - (void)sendData:(nonnull NSData *)data
           toAddress:(nonnull NSData *)remoteAddr
         withTimeout:(NSTimeInterval)timeout
                 tag:(long)tag;
    • You may optionally set a send filter for the socket.
    • A filter can provide several interesting possibilities:
    • 1. Optional caching of resolved addresses for domain names.
    • The cache could later be consulted, resulting in fewer system calls to getaddrinfo.
    • 2. Reusable modules of code for bandwidth monitoring.
    • 3. Sometimes traffic shapers are needed to simulate real world environments.
    • A filter allows you to write custom code to simulate such environments.
    • The ability to code this yourself is especially helpful when your simulated environment
    • is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router),
    • or the system tools to handle this aren’t available (e.g. on a mobile device).
    • For more information about FWAsyncUdpSocketSendFilterBlock, see the documentation for its typedef.
    • To remove a previously set filter, invoke this method and pass a nil filterBlock and NULL filterQueue.

    Note

    This method invokes setSendFilter:withQueue:isAsynchronous: (documented below),
    • passing YES for the isAsynchronous parameter.

    Declaration

    Objective-C

    - (void)setSendFilter:(nullable FWAsyncUdpSocketSendFilterBlock)filterBlock
                withQueue:(nullable dispatch_queue_t)filterQueue;
    • The receive filter can be run via dispatch_async or dispatch_sync.
    • Most typical situations call for asynchronous operation.
    • However, there are a few situations in which synchronous operation is preferred.
    • Such is the case when the filter is extremely minimal and fast.
    • This is because dispatch_sync is faster than dispatch_async.
    • If you choose synchronous operation, be aware of possible deadlock conditions.

    Since

    Since the socket queue is executing your block via dispatch_sync,
    • 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.

    Declaration

    Objective-C

    - (void)setSendFilter:(nullable FWAsyncUdpSocketSendFilterBlock)filterBlock
                withQueue:(nullable dispatch_queue_t)filterQueue
           isAsynchronous:(BOOL)isAsynchronous;

Receiving

    • There are two modes of operation for receiving packets: one-at-a-time & continuous.
    • In one-at-a-time mode, you call receiveOnce everytime your delegate is ready to process an incoming udp packet.
    • Receiving packets one-at-a-time may be better suited for implementing certain state machine code,
    • where your state machine may not always be ready to process incoming packets.
    • In continuous mode, the delegate is invoked immediately everytime incoming udp packets are received.
    • Receiving packets continuously is better suited to real-time streaming applications.
    • You may switch back and forth between one-at-a-time mode and continuous mode.
    • If the socket is currently in continuous mode, calling this method will switch it to one-at-a-time mode.
    • When a packet is received (and not filtered by the optional receive filter),
    • the delegate method (udpSocket:didReceiveData:fromAddress:withFilterContext:) is invoked.
    • If the socket is able to begin receiving packets, this method returns YES.
    • Otherwise it returns NO, and sets the errPtr with appropriate error information.
    • An example error:
    • You created a udp socket to act as a server, and immediately called receive.
    • You forgot to first bind the socket to a port number, and received a error with a message like:
    • “Must bind socket before you can receive data.”

    Declaration

    Objective-C

    - (BOOL)receiveOnce:(NSError *__autoreleasing _Nullable *_Nullable)errPtr;
    • There are two modes of operation for receiving packets: one-at-a-time & continuous.
    • In one-at-a-time mode, you call receiveOnce everytime your delegate is ready to process an incoming udp packet.
    • Receiving packets one-at-a-time may be better suited for implementing certain state machine code,
    • where your state machine may not always be ready to process incoming packets.
    • In continuous mode, the delegate is invoked immediately everytime incoming udp packets are received.
    • Receiving packets continuously is better suited to real-time streaming applications.
    • You may switch back and forth between one-at-a-time mode and continuous mode.
    • If the socket is currently in one-at-a-time mode, calling this method will switch it to continuous mode.
    • For every received packet (not filtered by the optional receive filter),
    • the delegate method (udpSocket:didReceiveData:fromAddress:withFilterContext:) is invoked.
    • If the socket is able to begin receiving packets, this method returns YES.
    • Otherwise it returns NO, and sets the errPtr with appropriate error information.
    • An example error:
    • You created a udp socket to act as a server, and immediately called receive.
    • You forgot to first bind the socket to a port number, and received a error with a message like:
    • “Must bind socket before you can receive data.”

    Declaration

    Objective-C

    - (BOOL)beginReceiving:(NSError *__autoreleasing _Nullable *_Nullable)errPtr;
    • If the socket is currently receiving (beginReceiving has been called), this method pauses the receiving.
    • That is, it won’t read any more packets from the underlying OS socket until beginReceiving is called again.

    Important

    Important Note:
    • FWAsyncUdpSocket may be running in parallel with your code.
    • That is, your delegate is likely running on a separate thread/dispatch_queue.
    • When you invoke this method, FWAsyncUdpSocket may have already dispatched delegate methods to be invoked.
    • Thus, if those delegate methods have already been dispatch_async’d,
    • your didReceive delegate method may still be invoked after this method has been called.
    • You should be aware of this, and program defensively.

    Declaration

    Objective-C

    - (void)pauseReceiving;
    • You may optionally set a receive filter for the socket.
    • This receive filter may be set to run in its own queue (independent of delegate queue).
    • A filter can provide several useful features.
    • 1. Many times udp packets need to be parsed.

    Since

    Since the filter can run in its own independent queue, you can parallelize this parsing quite easily.
    • The end result is a parallel socket io, datagram parsing, and packet processing.
    • 2. Many times udp packets are discarded because they are duplicate/unneeded/unsolicited.
    • The filter can prevent such packets from arriving at the delegate.
    • And because the filter can run in its own independent queue, this doesn’t slow down the delegate.
    • - Since the udp protocol does not guarantee delivery, udp packets may be lost.
    • Many protocols built atop udp thus provide various resend/re-request algorithms.
    • This sometimes results in duplicate packets arriving.
    • A filter may allow you to architect the duplicate detection code to run in parallel to normal processing.

    • - Since the udp socket may be connectionless, its possible for unsolicited packets to arrive.
    • Such packets need to be ignored.
    • 3. Sometimes traffic shapers are needed to simulate real world environments.
    • A filter allows you to write custom code to simulate such environments.
    • The ability to code this yourself is especially helpful when your simulated environment
    • is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router),
    • or the system tools to handle this aren’t available (e.g. on a mobile device).
    • Example:
    • FWAsyncUdpSocketReceiveFilterBlock filter = ^BOOL (NSData *data, NSData *address, id *context) {
    • MyProtocolMessage *msg = [MyProtocol parseMessage:data];

    • *context = response;
    • return (response != nil);
    • };
    • [udpSocket setReceiveFilter:filter withQueue:myParsingQueue];
    • For more information about FWAsyncUdpSocketReceiveFilterBlock, see the documentation for its typedef.
    • To remove a previously set filter, invoke this method and pass a nil filterBlock and NULL filterQueue.

    Note

    This method invokes setReceiveFilter:withQueue:isAsynchronous: (documented below),
    • passing YES for the isAsynchronous parameter.

    Declaration

    Objective-C

    - (void)setReceiveFilter:
                (nullable FWAsyncUdpSocketReceiveFilterBlock)filterBlock
                   withQueue:(nullable dispatch_queue_t)filterQueue;
    • The receive filter can be run via dispatch_async or dispatch_sync.
    • Most typical situations call for asynchronous operation.
    • However, there are a few situations in which synchronous operation is preferred.
    • Such is the case when the filter is extremely minimal and fast.
    • This is because dispatch_sync is faster than dispatch_async.
    • If you choose synchronous operation, be aware of possible deadlock conditions.

    Since

    Since the socket queue is executing your block via dispatch_sync,
    • 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.

    Declaration

    Objective-C

    - (void)setReceiveFilter:
                (nullable FWAsyncUdpSocketReceiveFilterBlock)filterBlock
                   withQueue:(nullable dispatch_queue_t)filterQueue
              isAsynchronous:(BOOL)isAsynchronous;

Closing

    • Immediately closes the underlying socket.
    • Any pending send operations are discarded.
    • The FWAsyncUdpSocket instance may optionally be used again.
    • (it will setup/configure/use another unnderlying BSD socket).

    Declaration

    Objective-C

    - (void)close;
    • Closes the underlying socket after all pending send operations have been sent.
    • The FWAsyncUdpSocket instance may optionally be used again.
    • (it will setup/configure/use another unnderlying BSD socket).

    Declaration

    Objective-C

    - (void)closeAfterSending;

Advanced

  • FWAsyncSocket maintains thread safety by using an internal serial dispatch_queue. In most cases, the instance creates this queue itself. However, to allow for maximum flexibility, the internal queue may be passed in the init method. This allows for some advanced options such as controlling socket priority via target queues. However, when one begins to use target queues like this, they open the door to some specific deadlock issues.

    For example, imagine there are 2 queues: dispatch_queue_t socketQueue; dispatch_queue_t socketTargetQueue;

    If you do this (pseudo-code): socketQueue.targetQueue = socketTargetQueue;

    Then all socketQueue operations will actually get run on the given socketTargetQueue. This is fine and works great in most situations. But if you run code directly from within the socketTargetQueue that accesses the socket, you could potentially get deadlock. Imagine the following code:

    • (BOOL)socketHasSomething { __block BOOL result = NO; dispatch_block_t block = ^{ result = [self someInternalMethodToBeRunOnlyOnSocketQueue]; } if (is_executing_on_queue(socketQueue)) block(); else dispatch_sync(socketQueue, block);

      return result; }

    What happens if you call this method from the socketTargetQueue? The result is deadlock. This is because the FW API offers no mechanism to discover a queue’s targetQueue. Thus we have no idea if our socketQueue is configured with a targetQueue. If we had this information, we could easily avoid deadlock. But, since these API’s are missing or unfeasible, you’ll have to explicitly set it.

    IF you pass a socketQueue via the init method, AND you’ve configured the passed socketQueue with a targetQueue, THEN you should pass the end queue in the target hierarchy.

    For example, consider the following queue hierarchy: socketQueue -> ipQueue -> moduleQueue

    This example demonstrates priority shaping within some server. All incoming client connections from the same IP address are executed on the same target queue. And all connections for a particular module are executed on the same target queue. Thus, the priority of all networking for the entire module can be changed on the fly. Additionally, networking traffic from a single IP cannot monopolize the module.

    Here’s how you would accomplish something like that:

    • (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(FWAsyncSocket *)sock { dispatch_queue_t socketQueue = dispatch_queue_create(“”, NULL); dispatch_queue_t ipQueue = [self ipQueueForAddress:address];

      dispatch_set_target_queue(socketQueue, ipQueue); dispatch_set_target_queue(iqQueue, moduleQueue);

      return socketQueue; }

    • (void)socket:(FWAsyncSocket *)sock didAcceptNewSocket:(FWAsyncSocket *)newSocket { [clientConnections addObject:newSocket]; [newSocket markSocketQueueTargetQueue:moduleQueue]; }

    Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue. This is often NOT the case, as such queues are used solely for execution shaping.

    Declaration

    Objective-C

    - (void)markSocketQueueTargetQueue:
        (nonnull dispatch_queue_t)socketQueuesPreConfiguredTargetQueue;
  • Undocumented

    Declaration

    Objective-C

    - (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue;
    • It’s not thread-safe to access certain variables from outside the socket’s internal queue.
    • For example, the socket file descriptor.
    • File descriptors are simply integers which reference an index in the per-process file table.
    • However, when one requests a new file descriptor (by opening a file or socket),
    • the file descriptor returned is guaranteed to be the lowest numbered unused descriptor.
    • So if we’re not careful, the following could be possible:
    • - Thread A invokes a method which returns the socket’s file descriptor.
    • - The socket is closed via the socket’s internal queue on thread B.
    • - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket’s FD.
    • - Thread A is now accessing/altering the file instead of the socket.
    • In addition to this, other variables are not actually objects,
    • and thus cannot be retained/released or even autoreleased.
    • An example is the sslContext, of type SSLContextRef, which is actually a malloc’d struct.
    • Although there are internal variables that make it difficult to maintain thread-safety,
    • it is important to provide access to these variables
    • to ensure this class can be used in a wide array of environments.
    • This method helps to accomplish this by invoking the current block on the socket’s internal queue.
    • The methods below can be invoked from within the block to access
    • those generally thread-unsafe internal variables in a thread-safe manner.
    • The given block will be invoked synchronously on the socket’s internal queue.
    • If you save references to any protected variables and use them outside the block, you do so at your own peril.

    Declaration

    Objective-C

    - (void)performBlock:(nonnull dispatch_block_t)block;
    • These methods are only available from within the context of a performBlock: invocation.

    See

    See the documentation for the performBlock: method above.
    • Provides access to the socket’s file descriptor(s).
    • If the socket isn’t connected, or explicity bound to a particular interface,
    • it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6.

    Declaration

    Objective-C

    - (int)socketFD;
  • Undocumented

    Declaration

    Objective-C

    - (int)socket4FD;
  • Undocumented

    Declaration

    Objective-C

    - (int)socket6FD;
    • These methods are only available from within the context of a performBlock: invocation.

    See

    See the documentation for the performBlock: method above.
    • Generally FWAsyncUdpSocket doesn’t use CFStream. (It uses the faster FW API’s.)
    • However, if you need one for any reason,
    • these methods are a convenient way to get access to a safe instance of one.

    Declaration

    Objective-C

    - (nullable CFReadStreamRef)readStream;
  • Undocumented

    Declaration

    Objective-C

    - (nullable CFWriteStreamRef)writeStream;

Utilities

    • Extracting host/port/family information from raw address data.

    Declaration

    Objective-C

    + (nullable NSString *)hostFromAddress:(nonnull NSData *)address;
  • Undocumented

    Declaration

    Objective-C

    + (uint16_t)portFromAddress:(NSData *)address;
  • Undocumented

    Declaration

    Objective-C

    + (int)familyFromAddress:(NSData *)address;
  • Undocumented

    Declaration

    Objective-C

    + (BOOL)isIPv4Address:(NSData *)address;
  • Undocumented

    Declaration

    Objective-C

    + (BOOL)isIPv6Address:(NSData *)address;
  • Undocumented

    Declaration

    Objective-C

    + (BOOL)getHost:(NSString * __nullable * __nullable)hostPtr port:(uint16_t * __nullable)portPtr fromAddress:(NSData *)address;
  • Undocumented

    Declaration

    Objective-C

    + (BOOL)getHost:(NSString * __nullable * __nullable)hostPtr port:(uint16_t * __nullable)portPtr family:(int * __nullable)afPtr fromAddress:(NSData *)address;