diff --git a/src/objective-c/NetworkBehavior.md b/src/objective-c/NetworkBehavior.md deleted file mode 100644 index ff66ea2340b..00000000000 --- a/src/objective-c/NetworkBehavior.md +++ /dev/null @@ -1,53 +0,0 @@ - -# gRPC iOS Network Transition Behaviors -On iOS devices, network transitions happen frequently. A device may have -multiple interfaces to connect to network, and these interfaces may become -broken or alive at any time. This document describes how these network changes -should be handled by gRPC and current issues related. - -## gRPC iOS with TCP Sockets -### Model -We classify network connectivity of the device at a given time in three -categories: WiFi, cellular, and none. The network connectivity information is -obtained from `SCNetworkReachability` API and the category is determined by -`SCNetworkReachabilityFlags` as follows: - -| Reachable | ConnectionRequired | IsWAAN | **Category** | -|:---------:|:------------------:|:------:|:------------:| -| 0 | X | X | None | -| X | 1 | X | None | -| 1 | 0 | 0 | WiFi | -| 1 | 0 | 1 | Cellular | - -Whenever there is a transition of network between these three categories, the -previous channels is assumed to be broken. If there is an unfinished call, the -call should return with status code `UNAVAILABLE`. All active gRPC channels -will be destroyed so that any new call will trigger creation of new channel -over new interface. In addition to that, when a TCP connection breaks, the -corresponding channel should also be destroyed and calls be canceled with -status code `UNAVAILABLE`. - -### Known issues -There are several issues related to BSD sockets known to us that causes -problems. - -* TCP socket stalls but does not return error when network status transits from - Cellular to WiFi. This problem is workarounded by - [ConnectivityMonitor](https://github.com/grpc/grpc/blob/master/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m). -* TCP socket stalls but does not return error when WiFi reconnects to another - hotspot while the app is in background. - -If you encounter these problems, the best solution is to switch to CFStream -implementation which eliminates all of them. - -## gRPC iOS with CFStream -gRPC iOS with CFStream implementation uses Apple's networking API to make -connections. It resolves the issues above that is known to TCP sockets on iOS. -Users are recommended to use this implementation rather than TCP socket -implementation. With CFStream implementation, a channel is broken when the -underlying stream detects an error or becomes closed. The behavior of streams -in CFStream are not documented by Apple, but our experiments show that it is -very similar to the model above, i.e. the streams error out when there is a -network connetivity change. So users should expect channels to break when the -network transits to another state and pending calls on those channels return -with status code `UNAVAILABLE`. diff --git a/src/objective-c/NetworkTransitionBehavior.md b/src/objective-c/NetworkTransitionBehavior.md new file mode 100644 index 00000000000..a0c2e781c4b --- /dev/null +++ b/src/objective-c/NetworkTransitionBehavior.md @@ -0,0 +1,86 @@ + +# gRPC iOS Network Transition Behaviors +Network connectivity on an iOS device may transition between cellular, WIFI, or +no network connectivity. This document describes how these network changes +should be handled by gRPC and current known issues. + +## Expected Network Transition Behaviors +The expected gRPC iOS channel and network transition behaviors are: +* Channel connection to a particular host is established at the time of + starting the first call to the channel and remains connected for future calls + to the same host. +* If the underlying connection to the remote host is broken, the channel is + disconnected and enters TRANSIENT\_FAILURE state. +* A channel is broken if the channel connection is no longer viable. This + happens when + * The network interface is no longer available, e.g. WiFi or cellular + interface is turned off or goes offline, airplane mode turned on, etc; + * The underlying TCP connection is no longer valid, e.g. WiFi connects to another hotspot, cellular data switched from LTE to 4G, etc; + * A network interface more preferable by the OS is valid, e.g. WiFi gets connected when the channel connects via cellular. +* A channel in TRANSIENT\_FAILURE state attempts reconnection on start of the + next call to the same host, but only after a certain backoff period (see + corresponding + [doc](https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md)). + During the backoff period, any call to the same host will wait until the + first of the following events occur: + * Connection succeeded; calls will be made using this channel; + * Conncetion failed; calls will be failed and return UNAVAILABLE status code; + * The call's deadline is reached; the call will fail and return + DEADLINE\_EXCEEDED status code. + +## Implementations +### gRPC iOS with TCP Sockets +gRPC's default implementation is to use TCP sockets for networking. It turns +out that although Apple supports this type of usage, it is [not recommended by +Apple](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/SocketsAndStreams/SocketsAndStreams.html) +and is also flawed. + +#### TCP Sockets Issues +The TCP sockets on iOS is flawed in that it does not reflect the viability of +the channel connection. Particularly, we found the following issues related to +TCP sockets: +* When a TCP sockets connection is established on cellular data and WiFi + becomes available, the TCP socket neither return an error event nor continue + sending/receiving data on it, but still accepts write on it. +* The TCP sockets does not report certain events that happens in the + background. When a TCP connection breaks in the background for the reason + like WiFi connects to another hotspot, the socket neither return an error nor + continue sending/receiving data on it, but still accepts write on it. + +#### gRPC iOS resolutions +We introduced +[`ConnectivityMonitor`](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/SocketsAndStreams/SocketsAndStreams.html) +in gRPC iOS library to alleviate these issues in TCP sockets, which changes the +network transition behaviors a bit. + +We classfy network connectivity state of the device into three categories based +on flags obtained from `SCNetworkReachability` API: + +| Reachable | ConnectionRequired | IsWWAN | **Category** | +|:---------:|:------------------:|:------:|:------------:| +| 0 | X | X | None | +| X | 1 | X | None | +| 1 | 0 | 0 | WiFi | +| 1 | 0 | 1 | Cellular | + +Whenever there is a transition of network between two of these categories, all +previously existing channels are assumed to be broken and are actively +destroyed. If there is an unfinished call, the call should return with status +code `UNAVAILABLE`. + +`ConnectivityMonitor` is able to detect the scenario of the first issue above +and actively destroy the channels. However, the second issue is not resolvable. +To solve that issue the best solution is to switch to CFStream implementation +which eliminates all of them. + +### gRPC iOS with CFStream +gRPC iOS with CFStream implementation uses Apple's networking API to make +connections. It resolves the issues above that is known to TCP sockets on iOS. +Users are recommended to use this implementation rather than TCP socket +implementation. The detailed behavior of streams in CFStream is not documented +by Apple, but our experiments show that it accords to the expected behaviors. +With CFStream implementation, an event is always received when the underlying +connection is no longer viable. For more detailed information and usages of +CFStream implementation, refer to the +[user guide](https://github.com/grpc/grpc/blob/master/src/objective-c/README-CFSTREAM.md). +