1*6777b538SAndroid Build Coastguard Worker# Chrome Network Stack Common Coding Patterns 2*6777b538SAndroid Build Coastguard Worker 3*6777b538SAndroid Build Coastguard Worker## Combined error and byte count into a single value 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard WorkerAt many places in the network stack, functions return a value that, if 6*6777b538SAndroid Build Coastguard Workerpositive, indicate a count of bytes that the the function read or 7*6777b538SAndroid Build Coastguard Workerwrote, and if negative, indicates a network stack error code (see 8*6777b538SAndroid Build Coastguard Worker[net_error_list.h][]). 9*6777b538SAndroid Build Coastguard WorkerZero indicates either `net::OK` or zero bytes read (usually EOF) 10*6777b538SAndroid Build Coastguard Workerdepending on the context. This pattern is generally specified by 11*6777b538SAndroid Build Coastguard Workeran `int` return type. 12*6777b538SAndroid Build Coastguard Worker 13*6777b538SAndroid Build Coastguard WorkerMany functions also have variables (often named `result` or `rv`) containing 14*6777b538SAndroid Build Coastguard Workersuch a value; this is especially common in the [DoLoop](#DoLoop) pattern 15*6777b538SAndroid Build Coastguard Workerdescribed below. 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker## Sync/Async Return 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard WorkerMany network stack routines may return synchronously or 20*6777b538SAndroid Build Coastguard Workerasynchronously. These functions generally return an int as described 21*6777b538SAndroid Build Coastguard Workerabove. There are three cases: 22*6777b538SAndroid Build Coastguard Worker 23*6777b538SAndroid Build Coastguard Worker* If the value is positive or zero, that indicates a synchronous 24*6777b538SAndroid Build Coastguard Worker successful return, with a zero return value indicating either zero 25*6777b538SAndroid Build Coastguard Worker bytes/EOF or indicating `net::OK`, depending on context. If there 26*6777b538SAndroid Build Coastguard Worker is a callback argument, it is not invoked. 27*6777b538SAndroid Build Coastguard Worker* If the value is negative and != `net::ERR_IO_PENDING`, it is an error 28*6777b538SAndroid Build Coastguard Worker code specifying a synchronous failure. If there is a callback argument, 29*6777b538SAndroid Build Coastguard Worker it is not invoked. 30*6777b538SAndroid Build Coastguard Worker* If the return value is the special value `net::ERR_IO_PENDING`, it 31*6777b538SAndroid Build Coastguard Worker indicates that the routine will complete asynchronously. A reference to 32*6777b538SAndroid Build Coastguard Worker any provided IOBuffer will be retained by the called entity until 33*6777b538SAndroid Build Coastguard Worker completion, to be written into or read from as required. 34*6777b538SAndroid Build Coastguard Worker If there is a callback argument, that callback will be called upon 35*6777b538SAndroid Build Coastguard Worker completion with the return value; if there is no callback argument, it 36*6777b538SAndroid Build Coastguard Worker usually means that some known callback mechanism will be employed. 37*6777b538SAndroid Build Coastguard Worker 38*6777b538SAndroid Build Coastguard Worker## DoLoop 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard WorkerThe DoLoop pattern is used in the network stack to construct simple 41*6777b538SAndroid Build Coastguard Workerstate machines. It is used for cases in which processing is basically 42*6777b538SAndroid Build Coastguard Workersingle-threaded and could be written in a single function, if that 43*6777b538SAndroid Build Coastguard Workerfunction could block waiting for input. Generally, initiation of a 44*6777b538SAndroid Build Coastguard Workerstate machine is triggered by some method invocation by a class 45*6777b538SAndroid Build Coastguard Workerconsumer, and that state machine is driven (possibly across 46*6777b538SAndroid Build Coastguard Workerasynchronous IO initiated by the class) until the operation requested 47*6777b538SAndroid Build Coastguard Workerby the method invocation completes, at which point the state variable is 48*6777b538SAndroid Build Coastguard Workerset to `STATE_NONE` and the consumer notified. 49*6777b538SAndroid Build Coastguard Worker 50*6777b538SAndroid Build Coastguard WorkerCases which do not fit into this single-threaded, single consumer 51*6777b538SAndroid Build Coastguard Workeroperation model are generally adapted in some way to fit the model, 52*6777b538SAndroid Build Coastguard Workereither by multiple state machines (e.g. independent state machines for 53*6777b538SAndroid Build Coastguard Workerreading and writing, if each can be initiated while the other is 54*6777b538SAndroid Build Coastguard Workeroutstanding) or by storing information across consumer invocations and 55*6777b538SAndroid Build Coastguard Workerreturns that can be used to restart the state machine in the proper 56*6777b538SAndroid Build Coastguard Workerstate. 57*6777b538SAndroid Build Coastguard Worker 58*6777b538SAndroid Build Coastguard WorkerAny class using this pattern will contain an enum listing all states 59*6777b538SAndroid Build Coastguard Workerof that machine, and define a function, `DoLoop()`, to drive that state 60*6777b538SAndroid Build Coastguard Workermachine. If a class has multiple state machines (as above) it will 61*6777b538SAndroid Build Coastguard Workerhave multiple methods (e.g. `DoReadLoop()` and `DoWriteLoop()`) to drive 62*6777b538SAndroid Build Coastguard Workerthose different machines. 63*6777b538SAndroid Build Coastguard Worker 64*6777b538SAndroid Build Coastguard WorkerThe characteristics of the DoLoop pattern are: 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Worker* Each state has a corresponding function which is called by `DoLoop()` 67*6777b538SAndroid Build Coastguard Worker for handling when the state machine is in that state. Generally the 68*6777b538SAndroid Build Coastguard Worker states are named STATE`_<`STATE_NAME`>` (upper case separated by 69*6777b538SAndroid Build Coastguard Worker underscores), and the routine is named Do`<`StateName`>` (CamelCase). 70*6777b538SAndroid Build Coastguard Worker For example: 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker enum State { 73*6777b538SAndroid Build Coastguard Worker STATE_NONE, 74*6777b538SAndroid Build Coastguard Worker STATE_INIT, 75*6777b538SAndroid Build Coastguard Worker STATE_FOO, 76*6777b538SAndroid Build Coastguard Worker STATE_FOO_COMPLETE, 77*6777b538SAndroid Build Coastguard Worker }; 78*6777b538SAndroid Build Coastguard Worker int DoInit(); 79*6777b538SAndroid Build Coastguard Worker int DoFoo(); 80*6777b538SAndroid Build Coastguard Worker int DoFooComplete(int result); 81*6777b538SAndroid Build Coastguard Worker 82*6777b538SAndroid Build Coastguard Worker* Each state handling function has two basic responsibilities in 83*6777b538SAndroid Build Coastguard Worker addition to state specific handling: Setting the data member 84*6777b538SAndroid Build Coastguard Worker (named `next_state_` or something similar) 85*6777b538SAndroid Build Coastguard Worker to specify the next state, and returning a `net::Error` (or combined 86*6777b538SAndroid Build Coastguard Worker error and byte count, as above). 87*6777b538SAndroid Build Coastguard Worker 88*6777b538SAndroid Build Coastguard Worker* On each `DoLoop()` iteration, the function saves the next state to a local 89*6777b538SAndroid Build Coastguard Worker variable and resets to a default state (`STATE_NONE`), 90*6777b538SAndroid Build Coastguard Worker and then calls the appropriate state handling based on the 91*6777b538SAndroid Build Coastguard Worker original value of the next state. This looks like: 92*6777b538SAndroid Build Coastguard Worker 93*6777b538SAndroid Build Coastguard Worker do { 94*6777b538SAndroid Build Coastguard Worker State state = io_state_; 95*6777b538SAndroid Build Coastguard Worker next_state_ = STATE_NONE; 96*6777b538SAndroid Build Coastguard Worker switch (state) { 97*6777b538SAndroid Build Coastguard Worker case STATE_INIT: 98*6777b538SAndroid Build Coastguard Worker result = DoInit(); 99*6777b538SAndroid Build Coastguard Worker break; 100*6777b538SAndroid Build Coastguard Worker ... 101*6777b538SAndroid Build Coastguard Worker 102*6777b538SAndroid Build Coastguard Worker This pattern is followed primarily to ensure that in the event of 103*6777b538SAndroid Build Coastguard Worker a bug where the next state isn't set, the loop terminates rather 104*6777b538SAndroid Build Coastguard Worker than loops infinitely. It's not a perfect mitigation, but works 105*6777b538SAndroid Build Coastguard Worker well as a defensive measure. 106*6777b538SAndroid Build Coastguard Worker 107*6777b538SAndroid Build Coastguard Worker* If a given state may complete asynchronously (for example, 108*6777b538SAndroid Build Coastguard Worker writing to an underlying transport socket), then there will often 109*6777b538SAndroid Build Coastguard Worker be split states, such as `STATE_WRITE` and 110*6777b538SAndroid Build Coastguard Worker `STATE_WRITE_COMPLETE`. The first state is responsible for 111*6777b538SAndroid Build Coastguard Worker starting/continuing the original operation, while the second state 112*6777b538SAndroid Build Coastguard Worker is responsible for handling completion (e.g. success vs error, 113*6777b538SAndroid Build Coastguard Worker complete vs. incomplete writes), and determining the next state to 114*6777b538SAndroid Build Coastguard Worker transition to. 115*6777b538SAndroid Build Coastguard Worker 116*6777b538SAndroid Build Coastguard Worker* While the return value from each call is propagated through the loop 117*6777b538SAndroid Build Coastguard Worker to the next state, it is expected that for most state transitions the 118*6777b538SAndroid Build Coastguard Worker return value will be `net::OK`, and that an error return will also 119*6777b538SAndroid Build Coastguard Worker set the state to `STATE_NONE` or fail to override the default 120*6777b538SAndroid Build Coastguard Worker assignment to `STATE_DONE` to exit the loop and return that 121*6777b538SAndroid Build Coastguard Worker error to the caller. This is often asserted with a DCHECK, e.g. 122*6777b538SAndroid Build Coastguard Worker 123*6777b538SAndroid Build Coastguard Worker case STATE_FOO: 124*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(result, OK); 125*6777b538SAndroid Build Coastguard Worker result = DoFoo(); 126*6777b538SAndroid Build Coastguard Worker break; 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker The exception to this pattern is split states, where an IO 129*6777b538SAndroid Build Coastguard Worker operation has been dispatched, and the second state is handling 130*6777b538SAndroid Build Coastguard Worker the result. In that case, the second state's function takes the 131*6777b538SAndroid Build Coastguard Worker result code: 132*6777b538SAndroid Build Coastguard Worker 133*6777b538SAndroid Build Coastguard Worker case STATE_FOO_COMPLETE: 134*6777b538SAndroid Build Coastguard Worker result = DoFooComplete(result); 135*6777b538SAndroid Build Coastguard Worker break; 136*6777b538SAndroid Build Coastguard Worker 137*6777b538SAndroid Build Coastguard Worker* If the return value from the state handling function is 138*6777b538SAndroid Build Coastguard Worker `net::ERR_IO_PENDING`, that indicates that the function has arranged 139*6777b538SAndroid Build Coastguard Worker for `DoLoop()` to be called at some point in the future, when further 140*6777b538SAndroid Build Coastguard Worker progress can be made on the state transitions. The `next_state_` variable 141*6777b538SAndroid Build Coastguard Worker will have been set to the proper value for handling that incoming 142*6777b538SAndroid Build Coastguard Worker call. In this case, `DoLoop()` will exit. This often occurs between 143*6777b538SAndroid Build Coastguard Worker split states, as described above. 144*6777b538SAndroid Build Coastguard Worker 145*6777b538SAndroid Build Coastguard Worker* The DoLoop mechanism is generally invoked in response to a consumer 146*6777b538SAndroid Build Coastguard Worker calling one of its methods. While the operation that method 147*6777b538SAndroid Build Coastguard Worker requested is occuring, the state machine stays active, possibly 148*6777b538SAndroid Build Coastguard Worker over multiple asynchronous operations and state transitions. When 149*6777b538SAndroid Build Coastguard Worker that operation is complete, the state machine transitions to 150*6777b538SAndroid Build Coastguard Worker `STATE_NONE` (by a `DoLoop()` callee not setting `next_state_`) or 151*6777b538SAndroid Build Coastguard Worker explicitly to `STATE_DONE` (indicating that the operation is 152*6777b538SAndroid Build Coastguard Worker complete *and* the state machine is not amenable to further 153*6777b538SAndroid Build Coastguard Worker driving). At this point the consumer is notified of the completion 154*6777b538SAndroid Build Coastguard Worker of the operation (by synchronous return or asynchronous callback). 155*6777b538SAndroid Build Coastguard Worker 156*6777b538SAndroid Build Coastguard Worker Note that this implies that when `DoLoop()` returns, one of two 157*6777b538SAndroid Build Coastguard Worker things will be true: 158*6777b538SAndroid Build Coastguard Worker 159*6777b538SAndroid Build Coastguard Worker * The return value will be `net::ERR_IO_PENDING`, indicating that the 160*6777b538SAndroid Build Coastguard Worker caller should take no action and instead wait for asynchronous 161*6777b538SAndroid Build Coastguard Worker notification. 162*6777b538SAndroid Build Coastguard Worker * The state of the machine will be either `STATE_DONE` or `STATE_NONE`, 163*6777b538SAndroid Build Coastguard Worker indicating that the operation that first initiated the `DoLoop()` has 164*6777b538SAndroid Build Coastguard Worker completed. 165*6777b538SAndroid Build Coastguard Worker 166*6777b538SAndroid Build Coastguard Worker This invariant reflects and enforces the single-threaded (though 167*6777b538SAndroid Build Coastguard Worker possibly asynchronous) nature of the driven state machine--the 168*6777b538SAndroid Build Coastguard Worker machine is always executing one requested operation. 169*6777b538SAndroid Build Coastguard Worker 170*6777b538SAndroid Build Coastguard Worker* `DoLoop()` is called from two places: a) methods exposed to the consumer 171*6777b538SAndroid Build Coastguard Worker for specific operations (e.g. `ReadHeaders()`), and b) an IO completion 172*6777b538SAndroid Build Coastguard Worker callbacks called asynchronously by spawned IO operations. 173*6777b538SAndroid Build Coastguard Worker 174*6777b538SAndroid Build Coastguard Worker In the first case, the return value from `DoLoop()` is returned directly 175*6777b538SAndroid Build Coastguard Worker to the caller; if the operation completed synchronously, that will 176*6777b538SAndroid Build Coastguard Worker contain the operation result, and if it completed asynchronously, it 177*6777b538SAndroid Build Coastguard Worker will be `net::ERR_IO_PENDING`. For example (from 178*6777b538SAndroid Build Coastguard Worker `HttpStreamParser`, abridged for clarity): 179*6777b538SAndroid Build Coastguard Worker 180*6777b538SAndroid Build Coastguard Worker int HttpStreamParser::ReadResponseHeaders( 181*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback) { 182*6777b538SAndroid Build Coastguard Worker DCHECK(io_state_ == STATE_NONE || io_state_ == STATE_DONE); 183*6777b538SAndroid Build Coastguard Worker DCHECK(callback_.is_null()); 184*6777b538SAndroid Build Coastguard Worker DCHECK(!callback.is_null()); 185*6777b538SAndroid Build Coastguard Worker 186*6777b538SAndroid Build Coastguard Worker int result = OK; 187*6777b538SAndroid Build Coastguard Worker io_state_ = STATE_READ_HEADERS; 188*6777b538SAndroid Build Coastguard Worker 189*6777b538SAndroid Build Coastguard Worker result = DoLoop(result); 190*6777b538SAndroid Build Coastguard Worker 191*6777b538SAndroid Build Coastguard Worker if (result == ERR_IO_PENDING) 192*6777b538SAndroid Build Coastguard Worker callback_ = std::move(callback); 193*6777b538SAndroid Build Coastguard Worker 194*6777b538SAndroid Build Coastguard Worker return result > 0 ? OK : result; 195*6777b538SAndroid Build Coastguard Worker } 196*6777b538SAndroid Build Coastguard Worker 197*6777b538SAndroid Build Coastguard Worker In the second case, the IO completion callback will examine the 198*6777b538SAndroid Build Coastguard Worker return value from `DoLoop()`. If it is `net::ERR_IO_PENDING`, no 199*6777b538SAndroid Build Coastguard Worker further action will be taken, and the IO completion callback will be 200*6777b538SAndroid Build Coastguard Worker called again at some future point. If it is not 201*6777b538SAndroid Build Coastguard Worker `net::ERR_IO_PENDING`, that is a signal that the operation has 202*6777b538SAndroid Build Coastguard Worker completed, and the IO completion callback will call the appropriate 203*6777b538SAndroid Build Coastguard Worker consumer callback to notify the consumer that the operation has 204*6777b538SAndroid Build Coastguard Worker completed. Note that it is important that this callback be done 205*6777b538SAndroid Build Coastguard Worker from the IO completion callback and not from `DoLoop()` or a 206*6777b538SAndroid Build Coastguard Worker `DoLoop()` callee, both to support the sync/async error return 207*6777b538SAndroid Build Coastguard Worker (DoLoop and its callees don't know the difference) and to avoid 208*6777b538SAndroid Build Coastguard Worker consumer callbacks deleting the object out from under `DoLoop()`. 209*6777b538SAndroid Build Coastguard Worker Example: 210*6777b538SAndroid Build Coastguard Worker 211*6777b538SAndroid Build Coastguard Worker void HttpStreamParser::OnIOComplete(int result) { 212*6777b538SAndroid Build Coastguard Worker result = DoLoop(result); 213*6777b538SAndroid Build Coastguard Worker 214*6777b538SAndroid Build Coastguard Worker if (result != ERR_IO_PENDING && !callback_.is_null()) 215*6777b538SAndroid Build Coastguard Worker std::move(callback_).Run(result); 216*6777b538SAndroid Build Coastguard Worker } 217*6777b538SAndroid Build Coastguard Worker 218*6777b538SAndroid Build Coastguard Worker* The DoLoop pattern has no concept of different events arriving for 219*6777b538SAndroid Build Coastguard Worker a single state; each state, if waiting, is waiting for one 220*6777b538SAndroid Build Coastguard Worker particular event, and when `DoLoop()` is invoked when the machine is 221*6777b538SAndroid Build Coastguard Worker in that state, it will handle that event. This reflects the 222*6777b538SAndroid Build Coastguard Worker single-threaded model for operations spawned by the state machine. 223*6777b538SAndroid Build Coastguard Worker 224*6777b538SAndroid Build Coastguard WorkerPublic class methods generally have very little processing, primarily wrapping 225*6777b538SAndroid Build Coastguard Worker`DoLoop()`. For `DoLoop()` entry this involves setting the `next_state_` 226*6777b538SAndroid Build Coastguard Workervariable, and possibly making copies of arguments into class members. For 227*6777b538SAndroid Build Coastguard Worker`DoLoop()` exit, it involves inspecting the return and passing it back to 228*6777b538SAndroid Build Coastguard Workerthe caller, and in the asynchronous case, saving any passed completion callback 229*6777b538SAndroid Build Coastguard Workerfor executing by a future subsidiary IO completion (see above example). 230*6777b538SAndroid Build Coastguard Worker 231*6777b538SAndroid Build Coastguard WorkerThis idiom allows synchronous and asynchronous logic to be written in 232*6777b538SAndroid Build Coastguard Workerthe same fashion; it's all just state transition handling. For mostly 233*6777b538SAndroid Build Coastguard Workerlinear state diagrams, the handling code can be very easy to 234*6777b538SAndroid Build Coastguard Workercomprehend, as such code is usually written linearly (in different 235*6777b538SAndroid Build Coastguard Workerhandling functions) in the order it's executed. 236*6777b538SAndroid Build Coastguard Worker 237*6777b538SAndroid Build Coastguard WorkerFor examples of this idiom, see 238*6777b538SAndroid Build Coastguard Worker 239*6777b538SAndroid Build Coastguard Worker* [HttpStreamParser::DoLoop](https://source.chromium.org/chromium/chromium/src/+/HEAD:net/http/http_stream_parser.cc). 240*6777b538SAndroid Build Coastguard Worker* [HttpNetworkTransaction::DoLoop](https://source.chromium.org/chromium/chromium/src/+/HEAD:net/http/http_network_transaction.cc) 241*6777b538SAndroid Build Coastguard Worker 242*6777b538SAndroid Build Coastguard Worker[net_error_list.h]: https://chromium.googlesource.com/chromium/src/+/main/net/base/net_error_list.h#1 243