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