xref: /aosp_15_r20/external/libwebsockets/lib/roles/README.md (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker## Information for new role implementers
2*1c60b9acSAndroid Build Coastguard Worker
3*1c60b9acSAndroid Build Coastguard Worker### Introduction
4*1c60b9acSAndroid Build Coastguard Worker
5*1c60b9acSAndroid Build Coastguard WorkerIn lws the "role" is the job the wsi is doing in the system, eg,
6*1c60b9acSAndroid Build Coastguard Workerbeing an http1 or h2, or ws connection, or being a listen socket, etc.
7*1c60b9acSAndroid Build Coastguard Worker
8*1c60b9acSAndroid Build Coastguard WorkerThis is different than, eg, a new ws protocol or a different callback
9*1c60b9acSAndroid Build Coastguard Workerfor an existing role.  A new role is needed when you want to add support for
10*1c60b9acSAndroid Build Coastguard Workersomething completely new, like a completely new wire protocol that
11*1c60b9acSAndroid Build Coastguard Workerdoesn't use http or ws.
12*1c60b9acSAndroid Build Coastguard Worker
13*1c60b9acSAndroid Build Coastguard WorkerSo... what's the point of implementing the protocol inside the lws role framework?
14*1c60b9acSAndroid Build Coastguard Worker
15*1c60b9acSAndroid Build Coastguard WorkerYou inherit all the well-maintained lws core functionality around:
16*1c60b9acSAndroid Build Coastguard Worker
17*1c60b9acSAndroid Build Coastguard Worker - connection lifecycle sequencing in a valgrind-clean way
18*1c60b9acSAndroid Build Coastguard Worker
19*1c60b9acSAndroid Build Coastguard Worker - client connection proxy support, for HTTP and Socks5
20*1c60b9acSAndroid Build Coastguard Worker
21*1c60b9acSAndroid Build Coastguard Worker - tls support working equally on mbedTLS and OpenSSL and derivatives without any code in the role
22*1c60b9acSAndroid Build Coastguard Worker
23*1c60b9acSAndroid Build Coastguard Worker - apis for cert lifecycle management and parsing
24*1c60b9acSAndroid Build Coastguard Worker
25*1c60b9acSAndroid Build Coastguard Worker - event loop support working on all the lws event loops (poll, libuv , ev, and event)
26*1c60b9acSAndroid Build Coastguard Worker
27*1c60b9acSAndroid Build Coastguard Worker - clean connection tracking and closing even on advanced event loops
28*1c60b9acSAndroid Build Coastguard Worker
29*1c60b9acSAndroid Build Coastguard Worker - user code follows the same simple callbacks on wsi
30*1c60b9acSAndroid Build Coastguard Worker
31*1c60b9acSAndroid Build Coastguard Worker - multi-vhost support
32*1c60b9acSAndroid Build Coastguard Worker
33*1c60b9acSAndroid Build Coastguard Worker - core multithreaded service support with usually no locking requirement on the role code
34*1c60b9acSAndroid Build Coastguard Worker
35*1c60b9acSAndroid Build Coastguard Worker - direct compatibility with all other lws roles + protocols in the same event loop
36*1c60b9acSAndroid Build Coastguard Worker
37*1c60b9acSAndroid Build Coastguard Worker - compatibility with higher-level stuff like lwsws as the server application
38*1c60b9acSAndroid Build Coastguard Worker
39*1c60b9acSAndroid Build Coastguard Worker### Code placement
40*1c60b9acSAndroid Build Coastguard Worker
41*1c60b9acSAndroid Build Coastguard WorkerThe code specific to that role should live in `./lib/roles/**role name**`
42*1c60b9acSAndroid Build Coastguard Worker
43*1c60b9acSAndroid Build Coastguard WorkerIf a role is asymmetic between a client and server side, like http is, it
44*1c60b9acSAndroid Build Coastguard Workershould generally be implemented as a single role.
45*1c60b9acSAndroid Build Coastguard Worker
46*1c60b9acSAndroid Build Coastguard Worker### Allowing control over enabling roles
47*1c60b9acSAndroid Build Coastguard Worker
48*1c60b9acSAndroid Build Coastguard WorkerAll roles should add a cmake define `LWS_ROLE_**role name**` and make its build
49*1c60b9acSAndroid Build Coastguard Workerdependent on it in CMakeLists.txt.  Export the cmakedefine in `./cmake/lws_config.h.in`
50*1c60b9acSAndroid Build Coastguard Workeras well so user builds can understand if the role is available in the lws build it is
51*1c60b9acSAndroid Build Coastguard Workertrying to bind to.
52*1c60b9acSAndroid Build Coastguard Worker
53*1c60b9acSAndroid Build Coastguard WorkerIf the role is disabled in cmake, nothing in its directory is built.
54*1c60b9acSAndroid Build Coastguard Worker
55*1c60b9acSAndroid Build Coastguard Worker### Role ops struct
56*1c60b9acSAndroid Build Coastguard Worker
57*1c60b9acSAndroid Build Coastguard WorkerThe role is defined by `struct lws_role_ops` in `lib/roles/private-lib-roles.h`,
58*1c60b9acSAndroid Build Coastguard Workereach role instantiates one of these and fills in the appropriate ops
59*1c60b9acSAndroid Build Coastguard Workercallbacks to perform its job.  By convention that lives in
60*1c60b9acSAndroid Build Coastguard Worker`./lib/roles/**role name**/ops-**role_name**.c`.
61*1c60b9acSAndroid Build Coastguard Worker
62*1c60b9acSAndroid Build Coastguard Worker### Private role declarations
63*1c60b9acSAndroid Build Coastguard Worker
64*1c60b9acSAndroid Build Coastguard WorkerTruly private declarations for the role can go in the role directory as you like.
65*1c60b9acSAndroid Build Coastguard WorkerHowever when the declarations must be accessible to other things in lws build, eg,
66*1c60b9acSAndroid Build Coastguard Workerthe role adds members to `struct lws` when enabled, they should be in the role
67*1c60b9acSAndroid Build Coastguard Workerdirectory in a file `private-lib-roles-myrole.h`.
68*1c60b9acSAndroid Build Coastguard Worker
69*1c60b9acSAndroid Build Coastguard WorkerSearch for "bring in role private declarations" in `./lib/roles/private-lib-roles.h
70*1c60b9acSAndroid Build Coastguard Workerand add your private role file there following the style used for the other roles,
71*1c60b9acSAndroid Build Coastguard Workereg,
72*1c60b9acSAndroid Build Coastguard Worker
73*1c60b9acSAndroid Build Coastguard Worker```
74*1c60b9acSAndroid Build Coastguard Worker#if defined(LWS_ROLE_WS)
75*1c60b9acSAndroid Build Coastguard Worker #include "roles/ws/private-lib-roles-ws.h"
76*1c60b9acSAndroid Build Coastguard Worker#else
77*1c60b9acSAndroid Build Coastguard Worker #define lwsi_role_ws(wsi) (0)
78*1c60b9acSAndroid Build Coastguard Worker#endif
79*1c60b9acSAndroid Build Coastguard Worker```
80*1c60b9acSAndroid Build Coastguard Worker
81*1c60b9acSAndroid Build Coastguard WorkerIf the role is disabled at cmake, nothing from its private.h should be used anywhere.
82*1c60b9acSAndroid Build Coastguard Worker
83*1c60b9acSAndroid Build Coastguard Worker### Integrating role assets to lws
84*1c60b9acSAndroid Build Coastguard Worker
85*1c60b9acSAndroid Build Coastguard WorkerIf your role needs special storage in lws objects, that's no problem.  But to keep
86*1c60b9acSAndroid Build Coastguard Workerthings sane, there are some rules.
87*1c60b9acSAndroid Build Coastguard Worker
88*1c60b9acSAndroid Build Coastguard Worker - declare a "container struct" in your private.h for everything, eg, the ws role wants
89*1c60b9acSAndroid Build Coastguard Worker   to add storage in lws_vhost for enabled extensions, it declares in its private.h
90*1c60b9acSAndroid Build Coastguard Worker
91*1c60b9acSAndroid Build Coastguard Worker```
92*1c60b9acSAndroid Build Coastguard Workerstruct lws_vhost_role_ws {
93*1c60b9acSAndroid Build Coastguard Worker#if !defined(LWS_WITHOUT_EXTENSIONS)
94*1c60b9acSAndroid Build Coastguard Worker	const struct lws_extension *extensions;
95*1c60b9acSAndroid Build Coastguard Worker#endif
96*1c60b9acSAndroid Build Coastguard Worker};
97*1c60b9acSAndroid Build Coastguard Worker```
98*1c60b9acSAndroid Build Coastguard Worker
99*1c60b9acSAndroid Build Coastguard Worker - add your role content in one place in the lws struct, protected by `#if defined(LWS_ROLE_**role name**)`,
100*1c60b9acSAndroid Build Coastguard Worker   eg, again for LWS_ROLE_WS
101*1c60b9acSAndroid Build Coastguard Worker
102*1c60b9acSAndroid Build Coastguard Worker```
103*1c60b9acSAndroid Build Coastguard Worker	struct lws_vhost {
104*1c60b9acSAndroid Build Coastguard Worker
105*1c60b9acSAndroid Build Coastguard Worker...
106*1c60b9acSAndroid Build Coastguard Worker
107*1c60b9acSAndroid Build Coastguard Worker#if defined(LWS_ROLE_WS)
108*1c60b9acSAndroid Build Coastguard Worker	struct lws_vhost_role_ws ws;
109*1c60b9acSAndroid Build Coastguard Worker#endif
110*1c60b9acSAndroid Build Coastguard Worker
111*1c60b9acSAndroid Build Coastguard Worker...
112*1c60b9acSAndroid Build Coastguard Worker```
113*1c60b9acSAndroid Build Coastguard Worker
114*1c60b9acSAndroid Build Coastguard Worker### Adding to lws available roles list
115*1c60b9acSAndroid Build Coastguard Worker
116*1c60b9acSAndroid Build Coastguard WorkerEdit the NULL-terminated array `available_roles` at the top of `./lib/core/context.c` to include
117*1c60b9acSAndroid Build Coastguard Workera pointer to your new role's ops struct, following the style already there.
118*1c60b9acSAndroid Build Coastguard Worker
119*1c60b9acSAndroid Build Coastguard Worker```
120*1c60b9acSAndroid Build Coastguard Workerconst struct lws_role_ops * available_roles[] = {
121*1c60b9acSAndroid Build Coastguard Worker#if defined(LWS_ROLE_H2)
122*1c60b9acSAndroid Build Coastguard Worker	&role_ops_h2,
123*1c60b9acSAndroid Build Coastguard Worker#endif
124*1c60b9acSAndroid Build Coastguard Worker...
125*1c60b9acSAndroid Build Coastguard Worker```
126*1c60b9acSAndroid Build Coastguard Worker
127*1c60b9acSAndroid Build Coastguard WorkerThis makes lws aware that your role exists, and it can auto-generate some things like
128*1c60b9acSAndroid Build Coastguard WorkerALPN lists, and call your role ops callbacks for things like hooking vhost creation.
129*1c60b9acSAndroid Build Coastguard Worker
130*1c60b9acSAndroid Build Coastguard Worker### Enabling role adoption
131*1c60b9acSAndroid Build Coastguard Worker
132*1c60b9acSAndroid Build Coastguard WorkerThe primary way wsi get bound to a specific role is via the lws adoption api
133*1c60b9acSAndroid Build Coastguard Worker`lws_adopt_descriptor_vhost()`.  Add flags as necessary in `./include/libwebsockets/lws-adopt.h`
134*1c60b9acSAndroid Build Coastguard Worker`enum lws_adoption_type` and follow the existing code in `lws_adopt_descriptor_vhost()`
135*1c60b9acSAndroid Build Coastguard Workerto bind a wsi with suitable flags to your role ops.
136*1c60b9acSAndroid Build Coastguard Worker
137*1c60b9acSAndroid Build Coastguard Worker### Implementation of the role
138*1c60b9acSAndroid Build Coastguard Worker
139*1c60b9acSAndroid Build Coastguard WorkerAfter that plumbing-in is completed, the role ops you declare are "live" on a wsi
140*1c60b9acSAndroid Build Coastguard Workerbound to them via the adoption api.
141*1c60b9acSAndroid Build Coastguard Worker
142*1c60b9acSAndroid Build Coastguard WorkerThe core support for wsis in lws has some generic concepts
143*1c60b9acSAndroid Build Coastguard Worker
144*1c60b9acSAndroid Build Coastguard Worker - the wsi holds a pointer member `role_ops` that indicates which role ops the
145*1c60b9acSAndroid Build Coastguard Worker   wsi is bound to
146*1c60b9acSAndroid Build Coastguard Worker
147*1c60b9acSAndroid Build Coastguard Worker - the wsi holds a generic uint32 `wsistate` that contains role flags and wsi state
148*1c60b9acSAndroid Build Coastguard Worker
149*1c60b9acSAndroid Build Coastguard Worker - role flags are provided (LWSIFR_CLIENT, LWSIFR_SERVER) to differentiate between
150*1c60b9acSAndroid Build Coastguard Worker   client and server connections inside a wsi, along with helpers `lwsi_role_client(wsi)`
151*1c60b9acSAndroid Build Coastguard Worker   and `lwsi_role_server(wsi)`.
152*1c60b9acSAndroid Build Coastguard Worker
153*1c60b9acSAndroid Build Coastguard Worker - lws provides around 30 generic states for the wsi starting from 'unconnected' through
154*1c60b9acSAndroid Build Coastguard Worker   various proxy or tunnel states, to 'established', and then various states shutting
155*1c60b9acSAndroid Build Coastguard Worker   down until 'dead socket'.  The states have testable flags and helpers to discover if
156*1c60b9acSAndroid Build Coastguard Worker   the wsi state is before establishment `lwsi_state_est(wsi)` and if in the state it is
157*1c60b9acSAndroid Build Coastguard Worker   in, it can handle pollout `lwsi_state_can_handle_POLLOUT(wsi)`.
158*1c60b9acSAndroid Build Coastguard Worker
159*1c60b9acSAndroid Build Coastguard Worker - You set the initial binding, role flags and state using `lws_role_transition()`.  Afterwards
160*1c60b9acSAndroid Build Coastguard Worker   you can adjust the state using `lwsi_set_state()`.
161*1c60b9acSAndroid Build Coastguard Worker
162*1c60b9acSAndroid Build Coastguard Worker### Role ops compression
163*1c60b9acSAndroid Build Coastguard Worker
164*1c60b9acSAndroid Build Coastguard WorkerSince the role ops struct is typically only sparsely filled, rather than have 20 function
165*1c60b9acSAndroid Build Coastguard Workerpointers most of which may be NULL, there is a separate array of a union of function
166*1c60b9acSAndroid Build Coastguard Workerpointers that is just long enough for functions that exist in the role, and a nybble index
167*1c60b9acSAndroid Build Coastguard Workertable with a nybble for each possible op, either 0 indicating that the operation is not
168*1c60b9acSAndroid Build Coastguard Workerprovided in this role, or 1 - 15 indicating the position of the function pointer in the
169*1c60b9acSAndroid Build Coastguard Workerarray.
170*1c60b9acSAndroid Build Coastguard Worker
171