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