1*1c60b9acSAndroid Build Coastguard Worker# `struct lws_sequencer` introduction 2*1c60b9acSAndroid Build Coastguard Worker 3*1c60b9acSAndroid Build Coastguard WorkerOften a single network action like a client GET is just part of a 4*1c60b9acSAndroid Build Coastguard Workerlarger series of actions, perhaps involving different connections. 5*1c60b9acSAndroid Build Coastguard Worker 6*1c60b9acSAndroid Build Coastguard WorkerSince lws operates inside an event loop, if the outer sequencing 7*1c60b9acSAndroid Build Coastguard Workerdoesn't, it can be awkward to synchronize these steps with what's 8*1c60b9acSAndroid Build Coastguard Workerhappening on the network with a particular connection on the event 9*1c60b9acSAndroid Build Coastguard Workerloop thread. 10*1c60b9acSAndroid Build Coastguard Worker 11*1c60b9acSAndroid Build Coastguard Worker 12*1c60b9acSAndroid Build Coastguard Worker 13*1c60b9acSAndroid Build Coastguard Worker`struct lws_sequencer` provides a generic way to stage multi-step 14*1c60b9acSAndroid Build Coastguard Workeroperations from inside the event loop. Because it participates 15*1c60b9acSAndroid Build Coastguard Workerin the event loop similar to a wsi, it always operates from the 16*1c60b9acSAndroid Build Coastguard Workerservice thread context and can access structures that share the 17*1c60b9acSAndroid Build Coastguard Workerservice thread without locking. It can also provide its own 18*1c60b9acSAndroid Build Coastguard Workerhigher-level timeout handling. 19*1c60b9acSAndroid Build Coastguard Worker 20*1c60b9acSAndroid Build Coastguard WorkerNaturally you can have many of them running in the same event 21*1c60b9acSAndroid Build Coastguard Workerloop operating independently. 22*1c60b9acSAndroid Build Coastguard Worker 23*1c60b9acSAndroid Build Coastguard WorkerSequencers themselves bind to a pt (per-thread) service thread, 24*1c60b9acSAndroid Build Coastguard Workerby default there's only one of these and it's the same as saying 25*1c60b9acSAndroid Build Coastguard Workerthey bind to an `lws_context`. The sequencer callback may create 26*1c60b9acSAndroid Build Coastguard Workerwsi which in turn are bound to a vhost, but the sequencer itself 27*1c60b9acSAndroid Build Coastguard Workeris above all that. 28*1c60b9acSAndroid Build Coastguard Worker 29*1c60b9acSAndroid Build Coastguard Worker## Sequencer timeouts 30*1c60b9acSAndroid Build Coastguard Worker 31*1c60b9acSAndroid Build Coastguard WorkerThe sequencer additionally maintains its own second-resolution timeout 32*1c60b9acSAndroid Build Coastguard Workerchecked by lws for the step being sequenced... this is independent of 33*1c60b9acSAndroid Build Coastguard Workerany lws wsi timeouts which tend to be set and reset for very short-term 34*1c60b9acSAndroid Build Coastguard Workertimeout protection inside one transaction. 35*1c60b9acSAndroid Build Coastguard Worker 36*1c60b9acSAndroid Build Coastguard WorkerThe sequencer timeout operates separately and above any wsi timeout, and 37*1c60b9acSAndroid Build Coastguard Workeris typically only reset by the sequencer callback when it receives an 38*1c60b9acSAndroid Build Coastguard Workerevent indicating a step completed or failed, or it sets up the next sequence 39*1c60b9acSAndroid Build Coastguard Workerstep. 40*1c60b9acSAndroid Build Coastguard Worker 41*1c60b9acSAndroid Build Coastguard WorkerIf the sequencer timeout expires, then the sequencer receives a queued 42*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_TIMED_OUT` message informing it, and it can take corrective action 43*1c60b9acSAndroid Build Coastguard Workeror schedule a retry of the step. This message is queued and sent normally 44*1c60b9acSAndroid Build Coastguard Workerunder the service thread context and in order of receipt. 45*1c60b9acSAndroid Build Coastguard Worker 46*1c60b9acSAndroid Build Coastguard WorkerUnlike lws timeouts which force the wsi to close, the sequencer timeout 47*1c60b9acSAndroid Build Coastguard Workeronly sends the message. This allows the timeout to be used to, eg, wait 48*1c60b9acSAndroid Build Coastguard Workerout a retry cooloff period and then start the retry when the 49*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_TIMED_OUT` is received, according to the state of the sequencer. 50*1c60b9acSAndroid Build Coastguard Worker 51*1c60b9acSAndroid Build Coastguard Worker## Creating an `struct lws_sequencer` 52*1c60b9acSAndroid Build Coastguard Worker 53*1c60b9acSAndroid Build Coastguard Worker``` 54*1c60b9acSAndroid Build Coastguard Workertypedef struct lws_seq_info { 55*1c60b9acSAndroid Build Coastguard Worker struct lws_context *context; /* lws_context for seq */ 56*1c60b9acSAndroid Build Coastguard Worker int tsi; /* thread service idx */ 57*1c60b9acSAndroid Build Coastguard Worker size_t user_size; /* size of user alloc */ 58*1c60b9acSAndroid Build Coastguard Worker void **puser; /* place ptr to user */ 59*1c60b9acSAndroid Build Coastguard Worker lws_seq_event_cb cb; /* seq callback */ 60*1c60b9acSAndroid Build Coastguard Worker const char *name; /* seq name */ 61*1c60b9acSAndroid Build Coastguard Worker const lws_retry_bo_t *retry; /* retry policy */ 62*1c60b9acSAndroid Build Coastguard Worker} lws_seq_info_t; 63*1c60b9acSAndroid Build Coastguard Worker``` 64*1c60b9acSAndroid Build Coastguard Worker 65*1c60b9acSAndroid Build Coastguard Worker``` 66*1c60b9acSAndroid Build Coastguard Workerstruct lws_sequencer * 67*1c60b9acSAndroid Build Coastguard Workerlws_sequencer_create(lws_seq_info_t *info); 68*1c60b9acSAndroid Build Coastguard Worker``` 69*1c60b9acSAndroid Build Coastguard Worker 70*1c60b9acSAndroid Build Coastguard WorkerWhen created, in lws the sequencer objects are bound to a 'per-thread', 71*1c60b9acSAndroid Build Coastguard Workerwhich is by default the same as to say bound to the `lws_context`. You 72*1c60b9acSAndroid Build Coastguard Workercan tag them with an opaque user data pointer, and they are also bound to 73*1c60b9acSAndroid Build Coastguard Workera user-specified callback which handles sequencer events 74*1c60b9acSAndroid Build Coastguard Worker 75*1c60b9acSAndroid Build Coastguard Worker``` 76*1c60b9acSAndroid Build Coastguard Workertypedef int (*lws_seq_event_cb)(struct lws_sequencer *seq, void *user_data, 77*1c60b9acSAndroid Build Coastguard Worker lws_seq_events_t event, void *data); 78*1c60b9acSAndroid Build Coastguard Worker``` 79*1c60b9acSAndroid Build Coastguard Worker 80*1c60b9acSAndroid Build Coastguard Worker`struct lws_sequencer` objects are private to lws and opaque to the user. A small 81*1c60b9acSAndroid Build Coastguard Workerset of apis lets you perform operations on the pointer returned by the 82*1c60b9acSAndroid Build Coastguard Workercreate api. 83*1c60b9acSAndroid Build Coastguard Worker 84*1c60b9acSAndroid Build Coastguard Worker## Queueing events on a sequencer 85*1c60b9acSAndroid Build Coastguard Worker 86*1c60b9acSAndroid Build Coastguard WorkerEach sequencer object can be passed "events", which are held on a per-sequencer 87*1c60b9acSAndroid Build Coastguard Workerqueue and handled strictly in the order they arrived on subsequent event loops. 88*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_CREATED` and `LWSSEQ_DESTROYED` events are produced by lws reflecting 89*1c60b9acSAndroid Build Coastguard Workerthe sequencer's lifecycle, but otherwise the event indexes have a user-defined 90*1c60b9acSAndroid Build Coastguard Workermeaning and are queued on the sequencer by user code for eventual consumption 91*1c60b9acSAndroid Build Coastguard Workerby user code in the sequencer callback. 92*1c60b9acSAndroid Build Coastguard Worker 93*1c60b9acSAndroid Build Coastguard WorkerPending events are removed from the sequencer queues and sent to the sequencer 94*1c60b9acSAndroid Build Coastguard Workercallback from inside the event loop at a rate of one per event loop wait. 95*1c60b9acSAndroid Build Coastguard Worker 96*1c60b9acSAndroid Build Coastguard Worker## Destroying sequencers 97*1c60b9acSAndroid Build Coastguard Worker 98*1c60b9acSAndroid Build Coastguard Worker`struct lws_sequencer` objects are cleaned up during context destruction if they are 99*1c60b9acSAndroid Build Coastguard Workerstill around. 100*1c60b9acSAndroid Build Coastguard Worker 101*1c60b9acSAndroid Build Coastguard WorkerNormally the sequencer callback receives a queued message that 102*1c60b9acSAndroid Build Coastguard Workerinforms it that it's either failed at the current step, or succeeded and that 103*1c60b9acSAndroid Build Coastguard Workerwas the last step, and requests that it should be destroyed by returning 104*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_RET_DESTROY` from the sequencer callback. 105*1c60b9acSAndroid Build Coastguard Worker 106*1c60b9acSAndroid Build Coastguard Worker## Lifecycle considerations 107*1c60b9acSAndroid Build Coastguard Worker 108*1c60b9acSAndroid Build Coastguard WorkerSequencers may spawn additional assets like client wsi as part of the sequenced 109*1c60b9acSAndroid Build Coastguard Workeractions... the lifecycle of the sequencer and the assets overlap but do not 110*1c60b9acSAndroid Build Coastguard Workernecessarily depend on each other... that is a wsi created by the sequencer may 111*1c60b9acSAndroid Build Coastguard Workeroutlive the sequencer. 112*1c60b9acSAndroid Build Coastguard Worker 113*1c60b9acSAndroid Build Coastguard WorkerIt's important therefore to detach assets from the sequencer and the sequencer 114*1c60b9acSAndroid Build Coastguard Workerfrom the assets when each step is over and the asset is "out of scope" for the 115*1c60b9acSAndroid Build Coastguard Workersequencer. It doesn't necessarily mean closing the assets, just making sure 116*1c60b9acSAndroid Build Coastguard Workerpointers are invalidated. For example, if a client wsi held a pointer to the 117*1c60b9acSAndroid Build Coastguard Workersequencer as its `.user_data`, when the wsi is out of scope for the sequencer 118*1c60b9acSAndroid Build Coastguard Workerit can set it to NULL, eg, `lws_set_wsi_user(wsi, NULL);`. 119*1c60b9acSAndroid Build Coastguard Worker 120*1c60b9acSAndroid Build Coastguard WorkerUnder some conditions wsi may want to hang around a bit to see if there is a 121*1c60b9acSAndroid Build Coastguard Workersubsequent client wsi transaction they can be reused on. They will clean 122*1c60b9acSAndroid Build Coastguard Workerthemselves up when they time out. 123*1c60b9acSAndroid Build Coastguard Worker 124*1c60b9acSAndroid Build Coastguard Worker## Watching wsi lifecycle from a sequencer 125*1c60b9acSAndroid Build Coastguard Worker 126*1c60b9acSAndroid Build Coastguard WorkerWhen a sequencer is creating a wsi as part of its sequence, it will be very 127*1c60b9acSAndroid Build Coastguard Workerinterested in lifecycle events. At client wsi creation time, the sequencer 128*1c60b9acSAndroid Build Coastguard Workercallback can set info->seq to itself in order to receive lifecycle messages 129*1c60b9acSAndroid Build Coastguard Workerabout its wsi. 130*1c60b9acSAndroid Build Coastguard Worker 131*1c60b9acSAndroid Build Coastguard Worker|message|meaning| 132*1c60b9acSAndroid Build Coastguard Worker|---|---| 133*1c60b9acSAndroid Build Coastguard Worker|`LWSSEQ_WSI_CONNECTED`|The wsi has become connected| 134*1c60b9acSAndroid Build Coastguard Worker|`LWSSEQ_WSI_CONN_FAIL`|The wsi has failed to connect| 135*1c60b9acSAndroid Build Coastguard Worker|`LWSSEQ_WSI_CONN_CLOSE`|The wsi had been connected, but has now closed| 136*1c60b9acSAndroid Build Coastguard Worker 137*1c60b9acSAndroid Build Coastguard WorkerBy receiving these, the sequencer can understand when it should attempt 138*1c60b9acSAndroid Build Coastguard Workerreconnections or that it cannot progress the sequence. 139*1c60b9acSAndroid Build Coastguard Worker 140*1c60b9acSAndroid Build Coastguard WorkerWhen dealing with wsi that were created by the sequencer, they may close at 141*1c60b9acSAndroid Build Coastguard Workerany time, eg, be closed by the remote peer or an intermediary. The 142*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_WSI_CONN_CLOSE` message may have been queued but since they are 143*1c60b9acSAndroid Build Coastguard Workerstrictly handled in the order they arrived, before it was 144*1c60b9acSAndroid Build Coastguard Workerhandled an earlier message may want to cause some api to be called on 145*1c60b9acSAndroid Build Coastguard Workerthe now-free()-d wsi. To detect this situation safely, there is a 146*1c60b9acSAndroid Build Coastguard Workersequencer api `lws_sequencer_check_wsi()` which peeks the message 147*1c60b9acSAndroid Build Coastguard Workerbuffer and returns nonzero if it later contains an `LWSSEQ_WSI_CONN_CLOSE` 148*1c60b9acSAndroid Build Coastguard Workeralready. 149*1c60b9acSAndroid Build Coastguard Worker 150