1 | /* |
2 | * libwebsockets - small server side websockets and web server implementation |
3 | * |
4 | * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to |
8 | * deal in the Software without restriction, including without limitation the |
9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
10 | * sell copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
22 | * IN THE SOFTWARE. |
23 | * |
24 | * lws_sequencer is intended to help implement sequences that: |
25 | * |
26 | * - outlive a single connection lifetime, |
27 | * - are not associated with a particular protocol, |
28 | * - are not associated with a particular vhost, |
29 | * - must receive and issue events inside the event loop |
30 | * |
31 | * lws_sequencer-s are bound to a pt (per-thread) which for the default case of |
32 | * one service thread is the same as binding to an lws_context. |
33 | */ |
34 | /* |
35 | * retry backoff table... retry n happens after .retry_ms_table[n] ms, with |
36 | * the last entry used if n is greater than the number of entries. |
37 | * |
38 | * The first .conceal_count retries are concealed, but after that the failures |
39 | * are reported. |
40 | */ |
41 | |
42 | typedef enum { |
43 | LWSSEQ_CREATED, /* sequencer created */ |
44 | LWSSEQ_DESTROYED, /* sequencer destroyed */ |
45 | LWSSEQ_TIMED_OUT, /* sequencer timeout */ |
46 | LWSSEQ_HEARTBEAT, /* 1Hz callback */ |
47 | |
48 | LWSSEQ_WSI_CONNECTED, /* wsi we bound to us has connected */ |
49 | LWSSEQ_WSI_CONN_FAIL, /* wsi we bound to us has failed to connect */ |
50 | LWSSEQ_WSI_CONN_CLOSE, /* wsi we bound to us has closed */ |
51 | |
52 | |
53 | LWSSEQ_SS_STATE_BASE, /* secure streams owned by a sequencer provide |
54 | * automatic messages about state changes on |
55 | * the sequencer, passing the oridinal in the |
56 | * event argument field. The message index is |
57 | * LWSSEQ_SS_STATE_BASE + the enum from |
58 | * lws_ss_constate_t */ |
59 | |
60 | LWSSEQ_USER_BASE = 100 /* define your events from here */ |
61 | } lws_seq_events_t; |
62 | |
63 | typedef enum lws_seq_cb_return { |
64 | LWSSEQ_RET_CONTINUE, |
65 | LWSSEQ_RET_DESTROY |
66 | } lws_seq_cb_return_t; |
67 | |
68 | /* |
69 | * handler for this sequencer. Return 0 if OK else nonzero to destroy the |
70 | * sequencer. LWSSEQ_DESTROYED will be called back to the handler so it can |
71 | * close / destroy any private assets associated with the sequence. |
72 | * |
73 | * The callback may return either LWSSEQ_RET_CONTINUE for the sequencer to |
74 | * resume or LWSSEQ_RET_DESTROY to indicate the sequence is finished. |
75 | * |
76 | * Event indexes consist of some generic ones but mainly user-defined ones |
77 | * starting from LWSSEQ_USER_BASE. |
78 | */ |
79 | typedef lws_seq_cb_return_t (*lws_seq_event_cb)(struct lws_sequencer *seq, |
80 | void *user, int event, void *data, void *aux); |
81 | |
82 | typedef struct lws_seq_info { |
83 | struct lws_context *context; /* lws_context for seq */ |
84 | int tsi; /* thread service idx */ |
85 | size_t user_size; /* size of user alloc */ |
86 | void **puser; /* place ptr to user */ |
87 | lws_seq_event_cb cb; /* seq callback */ |
88 | const char *name; /* seq name */ |
89 | const lws_retry_bo_t *retry; /* retry policy */ |
90 | uint8_t wakesuspend:1; /* important enough to |
91 | * wake system */ |
92 | } lws_seq_info_t; |
93 | |
94 | /** |
95 | * lws_seq_create() - create and bind sequencer to a pt |
96 | * |
97 | * \param info: information about sequencer to create |
98 | * |
99 | * This binds an abstract sequencer to a per-thread (by default, the single |
100 | * event loop of an lws_context). After the event loop starts, the sequencer |
101 | * will receive an LWSSEQ_CREATED event on its callback from the event loop |
102 | * context, where it can begin its sequence flow. |
103 | * |
104 | * Lws itself will only call the callback subsequently with LWSSEQ_DESTROYED |
105 | * when the sequencer is being destroyed. |
106 | * |
107 | * pt locking is used to protect the related data structures. |
108 | */ |
109 | LWS_VISIBLE LWS_EXTERN struct lws_sequencer * |
110 | lws_seq_create(lws_seq_info_t *info); |
111 | |
112 | /** |
113 | * lws_seq_destroy() - destroy the sequencer |
114 | * |
115 | * \param seq: pointer to the the opaque sequencer pointer returned by |
116 | * lws_seq_create() |
117 | * |
118 | * This proceeds to destroy the sequencer, calling LWSSEQ_DESTROYED and then |
119 | * freeing the sequencer object itself. The pointed-to seq pointer will be |
120 | * set to NULL. |
121 | */ |
122 | LWS_VISIBLE LWS_EXTERN void |
123 | lws_seq_destroy(struct lws_sequencer **seq); |
124 | |
125 | /** |
126 | * lws_seq_queue_event() - queue an event on the given sequencer |
127 | * |
128 | * \param seq: the opaque sequencer pointer returned by lws_seq_create() |
129 | * \param e: the event index to queue |
130 | * \param data: associated opaque (to lws) data to provide the callback |
131 | * \param aux: second opaque data to provide the callback |
132 | * |
133 | * This queues the event on a given sequencer. Queued events are delivered one |
134 | * per sequencer each subsequent time around the event loop, so the cb is called |
135 | * from the event loop thread context. |
136 | * |
137 | * Notice that because the events are delivered in order from the event loop, |
138 | * the scope of objects pointed to by \p data or \p aux may exceed the lifetime |
139 | * of the thing containing the pointed-to data. So it's usually better to pass |
140 | * values here. |
141 | */ |
142 | LWS_VISIBLE LWS_EXTERN int |
143 | lws_seq_queue_event(struct lws_sequencer *seq, lws_seq_events_t e, void *data, |
144 | void *aux); |
145 | |
146 | /** |
147 | * lws_seq_check_wsi() - check if wsi still extant |
148 | * |
149 | * \param seq: the sequencer interested in the wsi |
150 | * \param wsi: the wsi we want to confirm hasn't closed yet |
151 | * |
152 | * Check if wsi still extant, by peeking in the message queue for a |
153 | * LWSSEQ_WSI_CONN_CLOSE message about wsi. (Doesn't need to do the same for |
154 | * CONN_FAIL since that will never have produced any messages prior to that). |
155 | * |
156 | * Use this to avoid trying to perform operations on wsi that have already |
157 | * closed but we didn't get to that message yet. |
158 | * |
159 | * Returns 0 if not closed yet or 1 if it has closed but we didn't process the |
160 | * close message yet. |
161 | */ |
162 | LWS_VISIBLE LWS_EXTERN int |
163 | lws_seq_check_wsi(struct lws_sequencer *seq, struct lws *wsi); |
164 | |
165 | #define LWSSEQTO_NONE 0 |
166 | |
167 | /** |
168 | * lws_seq_timeout_us() - set a timeout by which the sequence must have |
169 | * completed by a different event or inform the |
170 | * sequencer |
171 | * |
172 | * \param seq: The sequencer to set the timeout on |
173 | * \param us: How many us in the future to fire the timeout |
174 | * LWS_SET_TIMER_USEC_CANCEL = cancel any existing timeout |
175 | * |
176 | * This api allows the sequencer to ask to be informed if it has not completed |
177 | * or disabled its timeout after secs seconds. Lws will send a LWSSEQ_TIMED_OUT |
178 | * event to the sequencer if the timeout expires. |
179 | * |
180 | * Typically the sequencer sets the timeout when starting a step, then waits to |
181 | * hear a queued event informing it the step completed or failed. The timeout |
182 | * provides a way to deal with the case the step neither completed nor failed |
183 | * within the timeout period. |
184 | * |
185 | * Lws wsi timeouts are not really suitable for this since they are focused on |
186 | * short-term protocol timeout protection and may be set and reset many times |
187 | * in one transaction. Wsi timeouts also enforce closure of the wsi when they |
188 | * trigger, sequencer timeouts have no side effect except to queue the |
189 | * LWSSEQ_TIMED_OUT message and leave it to the sequencer to decide how to |
190 | * react appropriately. |
191 | */ |
192 | LWS_VISIBLE LWS_EXTERN int |
193 | lws_seq_timeout_us(struct lws_sequencer *seq, lws_usec_t us); |
194 | |
195 | /** |
196 | * lws_seq_from_user(): get the lws_seq_t pointer from the user ptr |
197 | * |
198 | * \param u: the sequencer user allocation returned by lws_seq_create() or |
199 | * provided in the sequencer callback |
200 | * |
201 | * This gets the lws_seq_t * from the sequencer user allocation pointer. |
202 | * Actually these are allocated at the same time in one step, with the user |
203 | * allocation immediately after the lws_seq_t, so lws can compute where |
204 | * the lws_seq_t is from having the user allocation pointer. Since the |
205 | * size of the lws_seq_t is unknown to user code, this helper does it for |
206 | * you. |
207 | */ |
208 | LWS_VISIBLE LWS_EXTERN struct lws_sequencer * |
209 | lws_seq_from_user(void *u); |
210 | |
211 | /** |
212 | * lws_seq_us_since_creation(): elapsed seconds since sequencer created |
213 | * |
214 | * \param seq: pointer to the lws_seq_t |
215 | * |
216 | * Returns the number of us elapsed since the lws_seq_t was |
217 | * created. This is useful to calculate sequencer timeouts for the current |
218 | * step considering a global sequencer lifetime limit. |
219 | */ |
220 | LWS_VISIBLE LWS_EXTERN lws_usec_t |
221 | lws_seq_us_since_creation(struct lws_sequencer *seq); |
222 | |
223 | /** |
224 | * lws_seq_name(): get the name of this sequencer |
225 | * |
226 | * \param seq: pointer to the lws_seq_t |
227 | * |
228 | * Returns the name given when the sequencer was created. This is useful to |
229 | * annotate logging when then are multiple sequencers in play. |
230 | */ |
231 | LWS_VISIBLE LWS_EXTERN const char * |
232 | lws_seq_name(struct lws_sequencer *seq); |
233 | |
234 | /** |
235 | * lws_seq_get_context(): get the lws_context sequencer was created on |
236 | * |
237 | * \param seq: pointer to the lws_seq_t |
238 | * |
239 | * Returns the lws_context. Saves you having to store it if you have a seq |
240 | * pointer handy. |
241 | */ |
242 | LWS_VISIBLE LWS_EXTERN struct lws_context * |
243 | lws_seq_get_context(struct lws_sequencer *seq); |
244 | |