1Notes about coding with lws 2=========================== 3 4@section era Old lws and lws v2.0+ 5 6Originally lws only supported the "manual" method of handling everything in the 7user callback found in test-server.c / test-server-http.c. 8 9Since v2.0, the need for most or all of this manual boilerplate has been 10eliminated: the protocols[0] http stuff is provided by a generic lib export 11`lws_callback_http_dummy()`. You can serve parts of your filesystem at part of 12the URL space using mounts, the dummy http callback will do the right thing. 13 14It's much preferred to use the "automated" v2.0 type scheme, because it's less 15code and it's easier to support. 16 17The minimal examples all use the modern, recommended way. 18 19If you just need generic serving capability, without the need to integrate lws 20to some other app, consider not writing any server code at all, and instead use 21the generic server `lwsws`, and writing your special user code in a standalone 22"plugin". The server is configured for mounts etc using JSON, see 23./READMEs/README.lwsws.md. 24 25Although the "plugins" are dynamically loaded if you use lwsws or lws built 26with libuv, actually they may perfectly well be statically included if that 27suits your situation better, eg, ESP32 test server, where the platform does 28not support processes or dynamic loading, just #includes the plugins 29one after the other and gets the same benefit from the same code. 30 31Isolating and collating the protocol code in one place also makes it very easy 32to maintain and understand. 33 34So it if highly recommended you put your protocol-specific code into the 35form of a "plugin" at the source level, even if you have no immediate plan to 36use it dynamically-loaded. 37 38@section writeable Only send data when socket writeable 39 40You should only send data on a websocket connection from the user callback 41`LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for 42clients). 43 44If you want to send something, do NOT just send it but request a callback 45when the socket is writeable using 46 47 - `lws_callback_on_writable(wsi)` for a specific `wsi`, or 48 49 - `lws_callback_on_writable_all_protocol(protocol)` for all connections 50using that protocol to get a callback when next writeable. 51 52Usually you will get called back immediately next time around the service 53loop, but if your peer is slow or temporarily inactive the callback will be 54delayed accordingly. Generating what to write and sending it should be done 55in the ...WRITEABLE callback. 56 57See the test server code for an example of how to do this. 58 59Otherwise evolved libs like libuv get this wrong, they will allow you to "send" 60anything you want but it only uses up your local memory (and costs you 61memcpys) until the socket can actually accept it. It is much better to regulate 62your send action by the downstream peer readiness to take new data in the first 63place, avoiding all the wasted buffering. 64 65Libwebsockets' concept is that the downstream peer is truly the boss, if he, 66or our connection to him, cannot handle anything new, we should not generate 67anything new for him. This is how unix shell piping works, you may have 68`cat a.txt | grep xyz > remote", but actually that does not cat anything from 69a.txt while remote cannot accept anything new. 70 71@section oneper Only one lws_write per WRITEABLE callback 72 73From v2.5, lws strictly enforces only one lws_write() per WRITEABLE callback. 74 75You will receive a message about "Illegal back-to-back write of ... detected" 76if there is a second lws_write() before returning to the event loop. 77 78This is because with http/2, the state of the network connection carrying a 79wsi is unrelated to any state of the wsi. The situation on http/1 where a 80new request implied a new tcp connection and new SSL buffer, so you could 81assume some window for writes is no longer true. Any lws_write() can fail 82and be buffered for completion by lws; it will be auto-completed by the 83event loop. 84 85Note that if you are handling your own http responses, writing the headers 86needs to be done with a separate lws_write() from writing any payload. That 87means after writing the headers you must call `lws_callback_on_writable(wsi)` 88and send any payload from the writable callback. 89 90@section otherwr Do not rely on only your own WRITEABLE requests appearing 91 92Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events 93if it met network conditions where it had to buffer your send data internally. 94 95So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision 96about what to send, it can't assume that just because the writeable callback 97came something is ready to send. 98 99It's quite possible you get an 'extra' writeable callback at any time and 100just need to `return 0` and wait for the expected callback later. 101 102@section dae Daemonization 103 104There's a helper api `lws_daemonize` built by default that does everything you 105need to daemonize well, including creating a lock file. If you're making 106what's basically a daemon, just call this early in your init to fork to a 107headless background process and exit the starting process. 108 109Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your 110daemon is headless, so you'll need to sort out alternative logging, by, eg, 111syslog via `lws_set_log_level(..., lwsl_emit_syslog)`. 112 113@section conns Maximum number of connections 114 115The maximum number of connections the library can deal with is decided when 116it starts by querying the OS to find out how many file descriptors it is 117allowed to open (1024 on Fedora for example). It then allocates arrays that 118allow up to that many connections, minus whatever other file descriptors are 119in use by the user code. 120 121If you want to restrict that allocation, or increase it, you can use ulimit or 122similar to change the available number of file descriptors, and when restarted 123**libwebsockets** will adapt accordingly. 124 125@section peer_limits optional LWS_WITH_PEER_LIMITS 126 127If you select `LWS_WITH_PEER_LIMITS` at cmake, then lws will track peer IPs 128and monitor how many connections and ah resources they are trying to use 129at one time. You can choose to limit these at context creation time, using 130`info.ip_limit_ah` and `info.ip_limit_wsi`. 131 132Note that although the ah limit is 'soft', ie, the connection will just wait 133until the IP is under the ah limit again before attaching a new ah, the 134wsi limit is 'hard', lws will drop any additional connections from the 135IP until it's under the limit again. 136 137If you use these limits, you should consider multiple clients may simultaneously 138try to access the site through NAT, etc. So the limits should err on the side 139of being generous, while still making it impossible for one IP to exhaust 140all the server resources. 141 142@section evtloop Libwebsockets is singlethreaded 143 144Libwebsockets works in a serialized event loop, in a single thread. It supports 145the default poll() backend, and libuv, libev, and libevent event loop 146libraries that also take this locking-free, nonblocking event loop approach that 147is not threadsafe. There are several advantages to this technique, but one 148disadvantage, it doesn't integrate easily if there are multiple threads that 149want to use libwebsockets. 150 151However integration to multithreaded apps is possible if you follow some guidelines. 152 1531) Aside from two APIs, directly calling lws apis from other threads is not allowed. 154 1552) If you want to keep a list of live wsi, you need to use lifecycle callbacks on 156the protocol in the service thread to manage the list, with your own locking. 157Typically you use an ESTABLISHED callback to add ws wsi to your list and a CLOSED 158callback to remove them. 159 1603) LWS regulates your write activity by being able to let you know when you may 161write more on a connection. That reflects the reality that you cannot succeed to 162send data to a peer that has no room for it, so you should not generate or buffer 163write data until you know the peer connection can take more. 164 165Other libraries pretend that the guy doing the writing is the boss who decides 166what happens, and absorb as much as you want to write to local buffering. That does 167not scale to a lot of connections, because it will exhaust your memory and waste 168time copying data around in memory needlessly. 169 170The truth is the receiver, along with the network between you, is the boss who 171decides what will happen. If he stops accepting data, no data will move. LWS is 172designed to reflect that. 173 174If you have something to send, you call `lws_callback_on_writable()` on the 175connection, and when it is writeable, you will get a `LWS_CALLBACK_SERVER_WRITEABLE` 176callback, where you should generate the data to send and send it with `lws_write()`. 177 178You cannot send data using `lws_write()` outside of the WRITEABLE callback. 179 1804) For multithreaded apps, this corresponds to a need to be able to provoke the 181`lws_callback_on_writable()` action and to wake the service thread from its event 182loop wait (sleeping in `poll()` or `epoll()` or whatever). The rules above 183mean directly sending data on the connection from another thread is out of the 184question. 185 186The only lws api that's safe to call from other thread contexts is `lws_cancel_service()`. 187This will take a platform-specific action to wake the lws event loop thread wait, 188either put a byte into a pipe2() the event loop is waiting on, or send a packet on 189a UDP socket pair that the event loop waits on. When the wake is handled by the 190lws event loop thread, it will broadcast a `LWS_CALLBACK_EVENT_WAIT_CANCELLED` 191message to every vhost-protocol instantiation, so you can handle this callback, 192usually lock a shared data region, and if you see you need to write, call 193`lws_callback_on_writeable()` for the wsi(s) that need to write. 194 195There's no restriction on multiple threads calling `lws_cancel_service()`, it's 196unconditionally safe due to how it is implemented underneath. 197 1985) The obverse of this truism about the receiver being the boss is the case where 199we are receiving. If we get into a situation we actually can't usefully 200receive any more, perhaps because we are passing the data on and the guy we want 201to send to can't receive any more, then we should "turn off RX" by using the 202RX flow control API, `lws_rx_flow_control(wsi, 0)`. When something happens where we 203can accept more RX, (eg, we learn our onward connection is writeable) we can call 204it again to re-enable it on the incoming wsi. 205 206LWS stops calling back about RX immediately you use flow control to disable RX, it 207buffers the data internally if necessary. So you will only see RX when you can 208handle it. When flow control is disabled, LWS stops taking new data in... this makes 209the situation known to the sender by TCP "backpressure", the tx window fills and the 210sender finds he cannot write any more to the connection. 211 212See the mirror protocol implementations for example code. 213 214If you need to service other socket or file descriptors as well as the 215websocket ones, you can combine them together with the websocket ones 216in one poll loop, see "External Polling Loop support" below, and 217still do it all in one thread / process context. If the need is less 218architectural, you can also create RAW mode client and serving sockets; this 219is how the lws plugin for the ssh server works. 220 221@section anonprot Working without a protocol name 222 223Websockets allows connections to negotiate without a protocol name... 224in that case by default it will bind to the first protocol in your 225vhost protocols[] array. 226 227You can tell the vhost to use a different protocol by attaching a 228pvo (per-vhost option) to the 229 230``` 231/* 232 * this sets a per-vhost, per-protocol option name:value pair 233 * the effect is to set this protocol to be the default one for the vhost, 234 * ie, selected if no Protocol: header is sent with the ws upgrade. 235 */ 236 237static const struct lws_protocol_vhost_options pvo_opt = { 238 NULL, 239 NULL, 240 "default", 241 "1" 242}; 243 244static const struct lws_protocol_vhost_options pvo = { 245 NULL, 246 &pvo_opt, 247 "my-protocol", 248 "" 249}; 250 251... 252 253 context_info.pvo = &pvo; 254... 255 256``` 257 258Will select "my-protocol" from your protocol list (even if it came 259in by plugin) as being the target of client connections that don't 260specify a protocol. 261 262@section closing Closing connections from the user side 263 264When you want to close a connection, you do it by returning `-1` from a 265callback for that connection. 266 267You can provoke a callback by calling `lws_callback_on_writable` on 268the wsi, then notice in the callback you want to close it and just return -1. 269But usually, the decision to close is made in a callback already and returning 270-1 is simple. 271 272If the socket knows the connection is dead, because the peer closed or there 273was an affirmitive network error like a FIN coming, then **libwebsockets** will 274take care of closing the connection automatically. 275 276If you have a silently dead connection, it's possible to enter a state where 277the send pipe on the connection is choked but no ack will ever come, so the 278dead connection will never become writeable. To cover that, you can use TCP 279keepalives (see later in this document) or pings. 280 281@section gzip Serving from inside a zip file 282 283Lws now supports serving gzipped files from inside a zip container. Thanks to 284Per Bothner for contributing the code. 285 286This has the advtantage that if the client can accept GZIP encoding, lws can 287simply send the gzip-compressed file from inside the zip file with no further 288processing, saving time and bandwidth. 289 290In the case the client can't understand gzip compression, lws automatically 291decompressed the file and sends it normally. 292 293Clients with limited storage and RAM will find this useful; the memory needed 294for the inflate case is constrained so that only one input buffer at a time 295is ever in memory. 296 297To use this feature, ensure LWS_WITH_ZIP_FOPS is enabled at CMake. 298 299`libwebsockets-test-server-v2.0` includes a mount using this technology 300already, run that test server and navigate to http://localhost:7681/ziptest/candide.html 301 302This will serve the book Candide in html, together with two jpgs, all from 303inside a .zip file in /usr/[local/]share-libwebsockets-test-server/candide.zip 304 305Usage is otherwise automatic, if you arrange a mount that points to the zipfile, 306eg, "/ziptest" -> "mypath/test.zip", then URLs like `/ziptest/index.html` will be 307servied from `index.html` inside `mypath/test.zip` 308 309@section frags Fragmented messages 310 311To support fragmented messages you need to check for the final 312frame of a message with `lws_is_final_fragment`. This 313check can be combined with `libwebsockets_remaining_packet_payload` 314to gather the whole contents of a message, eg: 315 316``` 317 case LWS_CALLBACK_RECEIVE: 318 { 319 Client * const client = (Client *)user; 320 const size_t remaining = lws_remaining_packet_payload(wsi); 321 322 if (!remaining && lws_is_final_fragment(wsi)) { 323 if (client->HasFragments()) { 324 client->AppendMessageFragment(in, len, 0); 325 in = (void *)client->GetMessage(); 326 len = client->GetMessageLength(); 327 } 328 329 client->ProcessMessage((char *)in, len, wsi); 330 client->ResetMessage(); 331 } else 332 client->AppendMessageFragment(in, len, remaining); 333 } 334 break; 335``` 336 337The test app libwebsockets-test-fraggle sources also show how to 338deal with fragmented messages. 339 340 341@section debuglog Debug Logging 342 343See ./READMEs/README.logging.md 344 345@section asan Building with ASAN 346 347Under GCC you can select for the build to be instrumented with the Address 348Sanitizer, using `cmake .. -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_ASAN=1`. LWS is routinely run during development with valgrind, but ASAN is capable of finding different issues at runtime, like operations which are not strictly defined in the C 349standard and depend on platform behaviours. 350 351Run your application like this 352 353``` 354 $ sudo ASAN_OPTIONS=verbosity=2:halt_on_error=1 /usr/local/bin/lwsws 355``` 356 357and attach gdb to catch the place it halts. 358 359@section extpoll External Polling Loop support 360 361**libwebsockets** maintains an internal `poll()` array for all of its 362sockets, but you can instead integrate the sockets into an 363external polling array. That's needed if **libwebsockets** will 364cooperate with an existing poll array maintained by another 365server. 366 367Three callbacks `LWS_CALLBACK_ADD_POLL_FD`, `LWS_CALLBACK_DEL_POLL_FD` 368and `LWS_CALLBACK_CHANGE_MODE_POLL_FD` appear in the callback for protocol 0 369and allow interface code to manage socket descriptors in other poll loops. 370 371You can pass all pollfds that need service to `lws_service_fd()`, even 372if the socket or file does not belong to **libwebsockets** it is safe. 373 374If **libwebsocket** handled it, it zeros the pollfd `revents` field before returning. 375So you can let **libwebsockets** try and if `pollfd->revents` is nonzero on return, 376you know it needs handling by your code. 377 378Also note that when integrating a foreign event loop like libev or libuv where 379it doesn't natively use poll() semantics, and you must return a fake pollfd 380reflecting the real event: 381 382 - be sure you set .events to .revents value as well in the synthesized pollfd 383 384 - check the built-in support for the event loop if possible (eg, ./lib/libuv.c) 385 to see how it interfaces to lws 386 387 - use LWS_POLLHUP / LWS_POLLIN / LWS_POLLOUT from libwebsockets.h to avoid 388 losing windows compatibility 389 390You also need to take care about "forced service" somehow... these are cases 391where the network event was consumed, incoming data was all read, for example, 392but the work arising from it was not completed. There will not be any more 393network event to trigger the remaining work, Eg, we read compressed data, but 394we did not use up all the decompressed data before returning to the event loop 395because we had to write some of it. 396 397Lws provides an API to determine if anyone is waiting for forced service, 398`lws_service_adjust_timeout(context, 1, tsi)`, normally tsi is 0. If it returns 3990, then at least one connection has pending work you can get done by calling 400`lws_service_tsi(context, -1, tsi)`, again normally tsi is 0. 401 402For eg, the default poll() event loop, or libuv/ev/event, lws does this 403checking for you and handles it automatically. But in the external polling 404loop case, you must do it explicitly. Handling it after every normal service 405triggered by the external poll fd should be enough, since the situations needing 406it are initially triggered by actual network events. 407 408An example of handling it is shown in the test-server code specific to 409external polling. 410 411@section cpp Using with in c++ apps 412 413The library is ready for use by C++ apps. You can get started quickly by 414copying the test server 415 416``` 417 $ cp test-apps/test-server.c test.cpp 418``` 419 420and building it in C++ like this 421 422``` 423 $ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets 424``` 425 426`INSTALL_DATADIR` is only needed because the test server uses it as shipped, if 427you remove the references to it in your app you don't need to define it on 428the g++ line either. 429 430 431@section headerinfo Availability of header information 432 433HTTP Header information is managed by a pool of "ah" structs. These are a 434limited resource so there is pressure to free the headers and return the ah to 435the pool for reuse. 436 437For that reason header information on HTTP connections that get upgraded to 438websockets is lost after the ESTABLISHED callback. Anything important that 439isn't processed by user code before then should be copied out for later. 440 441For HTTP connections that don't upgrade, header info remains available the 442whole time. 443 444@section http2compat Code Requirements for HTTP/2 compatibility 445 446Websocket connections only work over http/1, so there is nothing special to do 447when you want to enable -DLWS_WITH_HTTP2=1. 448 449The internal http apis already follow these requirements and are compatible with 450http/2 already. So if you use stuff like mounts and serve stuff out of the 451filesystem, there's also nothing special to do. 452 453However if you are getting your hands dirty with writing response headers, or 454writing bulk data over http/2, you need to observe these rules so that it will 455work over both http/1.x and http/2 the same. 456 4571) LWS_PRE requirement applies on ALL lws_write(). For http/1, you don't have 458to take care of LWS_PRE for http data, since it is just sent straight out. 459For http/2, it will write up to LWS_PRE bytes behind the buffer start to create 460the http/2 frame header. 461 462This has implications if you treated the input buffer to lws_write() as const... 463it isn't any more with http/2, up to 9 bytes behind the buffer will be trashed. 464 4652) Headers are encoded using a sophisticated scheme in http/2. The existing 466header access apis are already made compatible for incoming headers, 467for outgoing headers you must: 468 469 - observe the LWS_PRE buffer requirement mentioned above 470 471 - Use `lws_add_http_header_status()` to add the transaction status (200 etc) 472 473 - use lws apis `lws_add_http_header_by_name()` and `lws_add_http_header_by_token()` 474 to put the headers into the buffer (these will translate what is actually 475 written to the buffer depending on if the connection is in http/2 mode or not) 476 477 - use the `lws api lws_finalize_http_header()` api after adding the last 478 response header 479 480 - write the header using lws_write(..., `LWS_WRITE_HTTP_HEADERS`); 481 482 3) http/2 introduces per-stream transmit credit... how much more you can send 483 on a stream is decided by the peer. You start off with some amount, as the 484 stream sends stuff lws will reduce your credit accordingly, when it reaches 485 zero, you must not send anything further until lws receives "more credit" for 486 that stream the peer. Lws will suppress writable callbacks if you hit 0 until 487 more credit for the stream appears, and lws built-in file serving (via mounts 488 etc) already takes care of observing the tx credit restrictions. However if 489 you write your own code that wants to send http data, you must consult the 490 `lws_get_peer_write_allowance()` api to find out the state of your tx credit. 491 For http/1, it will always return (size_t)-1, ie, no limit. 492 493 This is orthogonal to the question of how much space your local side's kernel 494 will make to buffer your send data on that connection. So although the result 495 from `lws_get_peer_write_allowance()` is "how much you can send" logically, 496 and may be megabytes if the peer allows it, you should restrict what you send 497 at one time to whatever your machine will generally accept in one go, and 498 further reduce that amount if `lws_get_peer_write_allowance()` returns 499 something smaller. If it returns 0, you should not consume or send anything 500 and return having asked for callback on writable, it will only come back when 501 more tx credit has arrived for your stream. 502 503 4) Header names with captital letters are illegal in http/2. Header names in 504 http/1 are case insensitive. So if you generate headers by name, change all 505 your header name strings to lower-case to be compatible both ways. 506 507 5) Chunked Transfer-encoding is illegal in http/2, http/2 peers will actively 508 reject it. Lws takes care of removing the header and converting CGIs that 509 emit chunked into unchunked automatically for http/2 connections. 510 511If you follow these rules, your code will automatically work with both http/1.x 512and http/2. 513 514@section ka TCP Keepalive 515 516It is possible for a connection which is not being used to send to die 517silently somewhere between the peer and the side not sending. In this case 518by default TCP will just not report anything and you will never get any more 519incoming data or sign the link is dead until you try to send. 520 521To deal with getting a notification of that situation, you can choose to 522enable TCP keepalives on all **libwebsockets** sockets, when you create the 523context. 524 525To enable keepalive, set the ka_time member of the context creation parameter 526struct to a nonzero value (in seconds) at context creation time. You should 527also fill ka_probes and ka_interval in that case. 528 529With keepalive enabled, the TCP layer will send control packets that should 530stimulate a response from the peer without affecting link traffic. If the 531response is not coming, the socket will announce an error at `poll()` forcing 532a close. 533 534Note that BSDs don't support keepalive time / probes / interval per-socket 535like Linux does. On those systems you can enable keepalive by a nonzero 536value in `ka_time`, but the systemwide kernel settings for the time / probes/ 537interval are used, regardless of what nonzero value is in `ka_time`. 538 539 540@section sslopt Optimizing SSL connections 541 542There's a member `ssl_cipher_list` in the `lws_context_creation_info` struct 543which allows the user code to restrict the possible cipher selection at 544context-creation time. 545 546You might want to look into that to stop the ssl peers selecting a cipher which 547is too computationally expensive. To use it, point it to a string like 548 549 `"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"` 550 551if left `NULL`, then the "DEFAULT" set of ciphers are all possible to select. 552 553You can also set it to `"ALL"` to allow everything (including insecure ciphers). 554 555 556@section sslcerts Passing your own cert information direct to SSL_CTX 557 558For most users it's enough to pass the SSL certificate and key information by 559giving filepaths to the info.ssl_cert_filepath and info.ssl_private_key_filepath 560members when creating the vhost. 561 562If you want to control that from your own code instead, you can do so by leaving 563the related info members NULL, and setting the info.options flag 564LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX at vhost creation time. That will create 565the vhost SSL_CTX without any certificate, and allow you to use the callback 566LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS to add your certificate to 567the SSL_CTX directly. The vhost SSL_CTX * is in the user parameter in that 568callback. 569 570@section clientasync Async nature of client connections 571 572When you call `lws_client_connect_info(..)` and get a `wsi` back, it does not 573mean your connection is active. It just means it started trying to connect. 574 575Your client connection is actually active only when you receive 576`LWS_CALLBACK_CLIENT_ESTABLISHED` for it. 577 578There's a 5 second timeout for the connection, and it may give up or die for 579other reasons, if any of that happens you'll get a 580`LWS_CALLBACK_CLIENT_CONNECTION_ERROR` callback on protocol 0 instead for the 581`wsi`. 582 583After attempting the connection and getting back a non-`NULL` `wsi` you should 584loop calling `lws_service()` until one of the above callbacks occurs. 585 586As usual, see [test-client.c](../test-apps/test-client.c) for example code. 587 588Notice that the client connection api tries to progress the connection 589somewhat before returning. That means it's possible to get callbacks like 590CONNECTION_ERROR on the new connection before your user code had a chance to 591get the wsi returned to identify it (in fact if the connection did fail early, 592NULL will be returned instead of the wsi anyway). 593 594To avoid that problem, you can fill in `pwsi` in the client connection info 595struct to point to a struct lws that get filled in early by the client 596connection api with the related wsi. You can then check for that in the 597callback to confirm the identity of the failing client connection. 598 599 600@section fileapi Lws platform-independent file access apis 601 602lws now exposes his internal platform file abstraction in a way that can be 603both used by user code to make it platform-agnostic, and be overridden or 604subclassed by user code. This allows things like handling the URI "directory 605space" as a virtual filesystem that may or may not be backed by a regular 606filesystem. One example use is serving files from inside large compressed 607archive storage without having to unpack anything except the file being 608requested. 609 610The test server shows how to use it, basically the platform-specific part of 611lws prepares a file operations structure that lives in the lws context. 612 613The user code can get a pointer to the file operations struct 614 615``` 616 LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops * 617 `lws_get_fops`(struct lws_context *context); 618``` 619 620and then can use helpers to also leverage these platform-independent 621file handling apis 622 623``` 624 lws_fop_fd_t 625 `lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename, 626 lws_fop_flags_t *flags) 627 int 628 `lws_plat_file_close`(lws_fop_fd_t fop_fd) 629 630 unsigned long 631 `lws_plat_file_seek_cur`(lws_fop_fd_t fop_fd, lws_fileofs_t offset) 632 633 int 634 `lws_plat_file_read`(lws_fop_fd_t fop_fd, lws_filepos_t *amount, 635 uint8_t *buf, lws_filepos_t len) 636 637 int 638 `lws_plat_file_write`(lws_fop_fd_t fop_fd, lws_filepos_t *amount, 639 uint8_t *buf, lws_filepos_t len ) 640``` 641 642Generic helpers are provided which provide access to generic fops information or 643call through to the above fops 644 645``` 646lws_filepos_t 647lws_vfs_tell(lws_fop_fd_t fop_fd); 648 649lws_filepos_t 650lws_vfs_get_length(lws_fop_fd_t fop_fd); 651 652uint32_t 653lws_vfs_get_mod_time(lws_fop_fd_t fop_fd); 654 655lws_fileofs_t 656lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset); 657 658lws_fileofs_t 659lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset); 660``` 661 662 663The user code can also override or subclass the file operations, to either 664wrap or replace them. An example is shown in test server. 665 666### Changes from v2.1 and before fops 667 668There are several changes: 669 6701) Pre-2.2 fops directly used platform file descriptors. Current fops returns and accepts a wrapper type lws_fop_fd_t which is a pointer to a malloc'd struct containing information specific to the filesystem implementation. 671 6722) Pre-2.2 fops bound the fops to a wsi. This is completely removed, you just give a pointer to the fops struct that applies to this file when you open it. Afterwards, the operations in the fops just need the lws_fop_fd_t returned from the open. 673 6743) Everything is wrapped in typedefs. See lws-plat-unix.c for examples of how to implement. 675 6764) Position in the file, File Length, and a copy of Flags left after open are now generically held in the fop_fd. 677VFS implementation must set and manage this generic information now. See the implementations in lws-plat-unix.c for 678examples. 679 6805) The file length is no longer set at a pointer provided by the open() fop. The api `lws_vfs_get_length()` is provided to 681get the file length after open. 682 6836) If your file namespace is virtual, ie, is not reachable by platform fops directly, you must set LWS_FOP_FLAG_VIRTUAL 684on the flags during open. 685 6867) There is an optional `mod_time` uint32_t member in the generic fop_fd. If you are able to set it during open, you 687should indicate it by setting `LWS_FOP_FLAG_MOD_TIME_VALID` on the flags. 688 689@section rawfd RAW file descriptor polling 690 691LWS allows you to include generic platform file descriptors in the lws service / poll / event loop. 692 693Open your fd normally and then 694 695``` 696 lws_sock_file_fd_type u; 697 698 u.filefd = your_open_file_fd; 699 700 if (!lws_adopt_descriptor_vhost(vhost, 0, u, 701 "protocol-name-to-bind-to", 702 optional_wsi_parent_or_NULL)) { 703 // failed 704 } 705 706 // OK 707``` 708 709A wsi is created for the file fd that acts like other wsi, you will get these 710callbacks on the named protocol 711 712``` 713 LWS_CALLBACK_RAW_ADOPT_FILE 714 LWS_CALLBACK_RAW_RX_FILE 715 LWS_CALLBACK_RAW_WRITEABLE_FILE 716 LWS_CALLBACK_RAW_CLOSE_FILE 717``` 718 719starting with LWS_CALLBACK_RAW_ADOPT_FILE. 720 721The minimal example `raw/minimal-raw-file` demonstrates how to use it. 722 723`protocol-lws-raw-test` plugin also provides a method for testing this with 724`libwebsockets-test-server-v2.0`: 725 726The plugin creates a FIFO on your system called "/tmp/lws-test-raw" 727 728You can feed it data through the FIFO like this 729 730``` 731 $ sudo sh -c "echo hello > /tmp/lws-test-raw" 732``` 733 734This plugin simply prints the data. But it does it through the lws event 735loop / service poll. 736 737@section rawsrvsocket RAW server socket descriptor polling 738 739You can also enable your vhost to accept RAW socket connections, in addition to 740HTTP[s] and WS[s]. If the first bytes written on the connection are not a 741valid HTTP method, then the connection switches to RAW mode. 742 743This is disabled by default, you enable it by setting the `.options` flag 744LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG, and setting 745`.listen_accept_role` to `"raw-skt"` when creating the vhost. 746 747RAW mode socket connections receive the following callbacks 748 749``` 750 LWS_CALLBACK_RAW_ADOPT 751 LWS_CALLBACK_RAW_RX 752 LWS_CALLBACK_RAW_WRITEABLE 753 LWS_CALLBACK_RAW_CLOSE 754``` 755 756You can control which protocol on your vhost handles these RAW mode 757incoming connections by setting the vhost info struct's `.listen_accept_protocol` 758to the vhost protocol name to use. 759 760`protocol-lws-raw-test` plugin provides a method for testing this with 761`libwebsockets-test-server-v2.0`: 762 763Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg 764 765``` 766 $ telnet 127.0.0.1 7681 767``` 768 769type something that isn't a valid HTTP method and enter, before the 770connection times out. The connection will switch to RAW mode using this 771protocol, and pass the unused rx as a raw RX callback. 772 773The test protocol echos back what was typed on telnet to telnet. 774 775@section rawclientsocket RAW client socket descriptor polling 776 777You can now also open RAW socket connections in client mode. 778 779Follow the usual method for creating a client connection, but set the 780`info.method` to "RAW". When the connection is made, the wsi will be 781converted to RAW mode and operate using the same callbacks as the 782server RAW sockets described above. 783 784The libwebsockets-test-client supports this using raw:// URLS. To 785test, open a netcat listener in one window 786 787``` 788 $ nc -l 9999 789``` 790 791and in another window, connect to it using the test client 792 793``` 794 $ libwebsockets-test-client raw://127.0.0.1:9999 795``` 796 797The connection should succeed, and text typed in the netcat window (including a CRLF) 798will be received in the client. 799 800@section rawudp RAW UDP socket integration 801 802Lws provides an api to create, optionally bind, and adopt a RAW UDP 803socket (RAW here means an uninterpreted normal UDP socket, not a 804"raw socket"). 805 806``` 807LWS_VISIBLE LWS_EXTERN struct lws * 808lws_create_adopt_udp(struct lws_vhost *vhost, int port, int flags, 809 const char *protocol_name, struct lws *parent_wsi); 810``` 811 812`flags` should be `LWS_CAUDP_BIND` if the socket will receive packets. 813 814The callbacks `LWS_CALLBACK_RAW_ADOPT`, `LWS_CALLBACK_RAW_CLOSE`, 815`LWS_CALLBACK_RAW_RX` and `LWS_CALLBACK_RAW_WRITEABLE` apply to the 816wsi. But UDP is different than TCP in some fundamental ways. 817 818For receiving on a UDP connection, data becomes available at 819`LWS_CALLBACK_RAW_RX` as usual, but because there is no specific 820connection with UDP, it is necessary to also get the source address of 821the data separately, using `struct lws_udp * lws_get_udp(wsi)`. 822You should take a copy of the `struct lws_udp` itself (not the 823pointer) and save it for when you want to write back to that peer. 824 825Writing is also a bit different for UDP. By default, the system has no 826idea about the receiver state and so asking for a `callback_on_writable()` 827always believes that the socket is writeable... the callback will 828happen next time around the event loop. 829 830With UDP, there is no single "connection". You need to write with sendto() and 831direct the packets to a specific destination. To return packets to a 832peer who sent something earlier and you copied his `struct lws_udp`, you 833use the .sa and .salen members as the last two parameters of the sendto(). 834 835The kernel may not accept to buffer / write everything you wanted to send. 836So you are responsible to watch the result of sendto() and resend the 837unsent part next time (which may involve adding new protocol headers to 838the remainder depending on what you are doing). 839 840@section ecdh ECDH Support 841 842ECDH Certs are now supported. Enable the CMake option 843 844 cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1 845 846**and** the info->options flag 847 848 LWS_SERVER_OPTION_SSL_ECDH 849 850to build in support and select it at runtime. 851 852@section sslinfo SSL info callbacks 853 854OpenSSL allows you to receive callbacks for various events defined in a 855bitmask in openssl/ssl.h. The events include stuff like TLS Alerts. 856 857By default, lws doesn't register for these callbacks. 858 859However if you set the info.ssl_info_event_mask to nonzero (ie, set some 860of the bits in it like `SSL_CB_ALERT` at vhost creation time, then 861connections to that vhost will call back using LWS_CALLBACK_SSL_INFO 862for the wsi, and the `in` parameter will be pointing to a struct of 863related args: 864 865``` 866struct lws_ssl_info { 867 int where; 868 int ret; 869}; 870``` 871 872The default callback handler in lws has a handler for LWS_CALLBACK_SSL_INFO 873which prints the related information, You can test it using the switch 874-S -s on `libwebsockets-test-server-v2.0`. 875 876Returning nonzero from the callback will close the wsi. 877 878@section smp SMP / Multithreaded service 879 880SMP support is integrated into LWS without any internal threading. It's 881very simple to use, libwebsockets-test-server-pthread shows how to do it, 882use -j n argument there to control the number of service threads up to 32. 883 884Two new members are added to the info struct 885 886 unsigned int count_threads; 887 unsigned int fd_limit_per_thread; 888 889leave them at the default 0 to get the normal singlethreaded service loop. 890 891Set count_threads to n to tell lws you will have n simultaneous service threads 892operating on the context. 893 894There is still a single listen socket on one port, no matter how many 895service threads. 896 897When a connection is made, it is accepted by the service thread with the least 898connections active to perform load balancing. 899 900The user code is responsible for spawning n threads running the service loop 901associated to a specific tsi (Thread Service Index, 0 .. n - 1). See 902the libwebsockets-test-server-pthread for how to do. 903 904If you leave fd_limit_per_thread at 0, then the process limit of fds is shared 905between the service threads; if you process was allowed 1024 fds overall then 906each thread is limited to 1024 / n. 907 908You can set fd_limit_per_thread to a nonzero number to control this manually, eg 909the overall supported fd limit is less than the process allowance. 910 911You can control the context basic data allocation for multithreading from Cmake 912using -DLWS_MAX_SMP=, if not given it's set to 1. The serv_buf allocation 913for the threads (currently 4096) is made at runtime only for active threads. 914 915Because lws will limit the requested number of actual threads supported 916according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to 917discover how many threads were actually allowed when the context was created. 918 919See the test-server-pthreads.c sample for how to use. 920 921@section smplocking SMP Locking Helpers 922 923Lws provide a set of pthread mutex helpers that reduce to no code or 924variable footprint in the case that LWS_MAX_SMP == 1. 925 926Define your user mutex like this 927 928``` 929 lws_pthread_mutex(name); 930``` 931 932If LWS_MAX_SMP > 1, this produces `pthread_mutex_t name;`. In the case 933LWS_MAX_SMP == 1, it produces nothing. 934 935Likewise these helpers for init, destroy, lock and unlock 936 937 938``` 939 void lws_pthread_mutex_init(pthread_mutex_t *lock) 940 void lws_pthread_mutex_destroy(pthread_mutex_t *lock) 941 void lws_pthread_mutex_lock(pthread_mutex_t *lock) 942 void lws_pthread_mutex_unlock(pthread_mutex_t *lock) 943``` 944 945resolve to nothing if LWS_MAX_SMP == 1, otherwise produce the equivalent 946pthread api. 947 948pthreads is required in lws only if LWS_MAX_SMP > 1. 949 950 951@section libevuv libev / libuv / libevent support 952 953You can select either or both 954 955 -DLWS_WITH_LIBEV=1 956 -DLWS_WITH_LIBUV=1 957 -DLWS_WITH_LIBEVENT=1 958 959at cmake configure-time. The user application may use one of the 960context init options flags 961 962 LWS_SERVER_OPTION_LIBEV 963 LWS_SERVER_OPTION_LIBUV 964 LWS_SERVER_OPTION_LIBEVENT 965 966to indicate it will use one of the event libraries at runtime. 967 968libev and libevent headers conflict, they both define critical constants like 969EV_READ to different values. Attempts to discuss clearing that up with both 970libevent and libev did not get anywhere useful. Therefore CMakeLists.txt will 971error out if you enable both LWS_WITH_LIBEV and LWS_WITH_LIBEVENT. 972 973In addition depending on libev / compiler version, building anything with libev 974apis using gcc may blow strict alias warnings (which are elevated to errors in 975lws). I did some googling at found these threads related to it, the issue goes 976back at least to 2010 on and off 977 978https://github.com/redis/hiredis/issues/434 979https://bugs.gentoo.org/show_bug.cgi?id=615532 980http://lists.schmorp.de/pipermail/libev/2010q1/000916.html 981http://lists.schmorp.de/pipermail/libev/2010q1/000920.html 982http://lists.schmorp.de/pipermail/libev/2010q1/000923.html 983 984We worked around this problem by disabling -Werror on the parts of lws that 985use libev. FWIW as of Dec 2019 using Fedora 31 libev 4.27.1 and its gcc 9.2.1 986doesn't seem to trigger the problem even without the workaround. 987 988For these reasons and the response I got trying to raise these issues with 989them, if you have a choice about event loop, I would gently encourage you 990to avoid libev. Where lws uses an event loop itself, eg in lwsws, we use 991libuv. 992 993@section extopts Extension option control from user code 994 995User code may set per-connection extension options now, using a new api 996`lws_set_extension_option()`. 997 998This should be called from the ESTABLISHED callback like this 999``` 1000 lws_set_extension_option(wsi, "permessage-deflate", 1001 "rx_buf_size", "12"); /* 1 << 12 */ 1002``` 1003 1004If the extension is not active (missing or not negotiated for the 1005connection, or extensions are disabled on the library) the call is 1006just returns -1. Otherwise the connection's extension has its 1007named option changed. 1008 1009The extension may decide to alter or disallow the change, in the 1010example above permessage-deflate restricts the size of his rx 1011output buffer also considering the protocol's rx_buf_size member. 1012 1013 1014@section httpsclient Client connections as HTTP[S] rather than WS[S] 1015 1016You may open a generic http client connection using the same 1017struct lws_client_connect_info used to create client ws[s] 1018connections. 1019 1020To stay in http[s], set the optional info member "method" to 1021point to the string "GET" instead of the default NULL. 1022 1023After the server headers are processed, when payload from the 1024server is available the callback LWS_CALLBACK_RECEIVE_CLIENT_HTTP 1025will be made. 1026 1027You can choose whether to process the data immediately, or 1028queue a callback when an outgoing socket is writeable to provide 1029flow control, and process the data in the writable callback. 1030 1031Either way you use the api `lws_http_client_read()` to access the 1032data, eg 1033 1034``` 1035 case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: 1036 { 1037 char buffer[1024 + LWS_PRE]; 1038 char *px = buffer + LWS_PRE; 1039 int lenx = sizeof(buffer) - LWS_PRE; 1040 1041 lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n"); 1042 1043 /* 1044 * Often you need to flow control this by something 1045 * else being writable. In that case call the api 1046 * to get a callback when writable here, and do the 1047 * pending client read in the writeable callback of 1048 * the output. 1049 */ 1050 if (lws_http_client_read(wsi, &px, &lenx) < 0) 1051 return -1; 1052 while (lenx--) 1053 putchar(*px++); 1054 } 1055 break; 1056``` 1057 1058Notice that if you will use SSL client connections on a vhost, you must 1059prepare the client SSL context for the vhost after creating the vhost, since 1060this is not normally done if the vhost was set up to listen / serve. Call 1061the api lws_init_vhost_client_ssl() to also allow client SSL on the vhost. 1062 1063@section clipipe Pipelining Client Requests to same host 1064 1065If you are opening more client requests to the same host and port, you 1066can give the flag LCCSCF_PIPELINE on `info.ssl_connection` to indicate 1067you wish to pipeline them. 1068 1069Without the flag, the client connections will occur concurrently using a 1070socket and tls wrapper if requested for each connection individually. 1071That is fast, but resource-intensive. 1072 1073With the flag, lws will queue subsequent client connections on the first 1074connection to the same host and port. When it has confirmed from the 1075first connection that pipelining / keep-alive is supported by the server, 1076it lets the queued client pipeline connections send their headers ahead 1077of time to create a pipeline of requests on the server side. 1078 1079In this way only one tcp connection and tls wrapper is required to transfer 1080all the transactions sequentially. It takes a little longer but it 1081can make a significant difference to resources on both sides. 1082 1083If lws learns from the first response header that keepalive is not possible, 1084then it marks itself with that information and detaches any queued clients 1085to make their own individual connections as a fallback. 1086 1087Lws can also intelligently combine multiple ongoing client connections to 1088the same host and port into a single http/2 connection with multiple 1089streams if the server supports it. 1090 1091Unlike http/1 pipelining, with http/2 the client connections all occur 1092simultaneously using h2 stream multiplexing inside the one tcp + tls 1093connection. 1094 1095You can turn off the h2 client support either by not building lws with 1096`-DLWS_WITH_HTTP2=1` or giving the `LCCSCF_NOT_H2` flag in the client 1097connection info struct `ssl_connection` member. 1098 1099@section vhosts Using lws vhosts 1100 1101If you set LWS_SERVER_OPTION_EXPLICIT_VHOSTS options flag when you create 1102your context, it won't create a default vhost using the info struct 1103members for compatibility. Instead you can call lws_create_vhost() 1104afterwards to attach one or more vhosts manually. 1105 1106``` 1107 LWS_VISIBLE struct lws_vhost * 1108 lws_create_vhost(struct lws_context *context, 1109 struct lws_context_creation_info *info); 1110``` 1111 1112lws_create_vhost() uses the same info struct as lws_create_context(), 1113it ignores members related to context and uses the ones meaningful 1114for vhost (marked with VH in libwebsockets.h). 1115 1116``` 1117 struct lws_context_creation_info { 1118 int port; /* VH */ 1119 const char *iface; /* VH */ 1120 const struct lws_protocols *protocols; /* VH */ 1121 const struct lws_extension *extensions; /* VH */ 1122 ... 1123``` 1124 1125When you attach the vhost, if the vhost's port already has a listen socket 1126then both vhosts share it and use SNI (is SSL in use) or the Host: header 1127from the client to select the right one. Or if no other vhost already 1128listening the a new listen socket is created. 1129 1130There are some new members but mainly it's stuff you used to set at 1131context creation time. 1132 1133 1134@section sni How lws matches hostname or SNI to a vhost 1135 1136LWS first strips any trailing :port number. 1137 1138Then it tries to find an exact name match for a vhost listening on the correct 1139port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a 1140vhost named abc.com that is listening on port 1234. 1141 1142If there is no exact match, lws will consider wildcard matches, for example 1143if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will 1144accept a vhost "abc.com" listening on port 1234. If there was a better, exact, 1145match, it will have been chosen in preference to this. 1146 1147Connections with SSL will still have the client go on to check the 1148certificate allows wildcards and error out if not. 1149 1150 1151 1152@section mounts Using lws mounts on a vhost 1153 1154The last argument to lws_create_vhost() lets you associate a linked 1155list of lws_http_mount structures with that vhost's URL 'namespace', in 1156a similar way that unix lets you mount filesystems into areas of your / 1157filesystem how you like and deal with the contents transparently. 1158 1159``` 1160 struct lws_http_mount { 1161 struct lws_http_mount *mount_next; 1162 const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */ 1163 const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */ 1164 const char *def; /* default target, eg, "index.html" */ 1165 1166 struct lws_protocol_vhost_options *cgienv; 1167 1168 int cgi_timeout; 1169 int cache_max_age; 1170 1171 unsigned int cache_reusable:1; 1172 unsigned int cache_revalidate:1; 1173 unsigned int cache_intermediaries:1; 1174 1175 unsigned char origin_protocol; 1176 unsigned char mountpoint_len; 1177 }; 1178``` 1179 1180The last mount structure should have a NULL mount_next, otherwise it should 1181point to the 'next' mount structure in your list. 1182 1183Both the mount structures and the strings must persist until the context is 1184destroyed, since they are not copied but used in place. 1185 1186`.origin_protocol` should be one of 1187 1188``` 1189 enum { 1190 LWSMPRO_HTTP, 1191 LWSMPRO_HTTPS, 1192 LWSMPRO_FILE, 1193 LWSMPRO_CGI, 1194 LWSMPRO_REDIR_HTTP, 1195 LWSMPRO_REDIR_HTTPS, 1196 LWSMPRO_CALLBACK, 1197 }; 1198``` 1199 1200 - LWSMPRO_FILE is used for mapping url namespace to a filesystem directory and 1201serve it automatically. 1202 1203 - LWSMPRO_CGI associates the url namespace with the given CGI executable, which 1204runs when the URL is accessed and the output provided to the client. 1205 1206 - LWSMPRO_REDIR_HTTP and LWSMPRO_REDIR_HTTPS auto-redirect clients to the given 1207origin URL. 1208 1209 - LWSMPRO_CALLBACK causes the http connection to attach to the callback 1210associated with the named protocol (which may be a plugin). 1211 1212 1213@section mountcallback Operation of LWSMPRO_CALLBACK mounts 1214 1215The feature provided by CALLBACK type mounts is binding a part of the URL 1216namespace to a named protocol callback handler. 1217 1218This allows protocol plugins to handle areas of the URL namespace. For example 1219in test-server-v2.0.c, the URL area "/formtest" is associated with the plugin 1220providing "protocol-post-demo" like this 1221 1222``` 1223 static const struct lws_http_mount mount_post = { 1224 NULL, /* linked-list pointer to next*/ 1225 "/formtest", /* mountpoint in URL namespace on this vhost */ 1226 "protocol-post-demo", /* handler */ 1227 NULL, /* default filename if none given */ 1228 NULL, 1229 0, 1230 0, 1231 0, 1232 0, 1233 0, 1234 LWSMPRO_CALLBACK, /* origin points to a callback */ 1235 9, /* strlen("/formtest"), ie length of the mountpoint */ 1236 }; 1237``` 1238 1239Client access to /formtest[anything] will be passed to the callback registered 1240with the named protocol, which in this case is provided by a protocol plugin. 1241 1242Access by all methods, eg, GET and POST are handled by the callback. 1243 1244protocol-post-demo deals with accepting and responding to the html form that 1245is in the test server HTML. 1246 1247When a connection accesses a URL related to a CALLBACK type mount, the 1248connection protocol is changed until the next access on the connection to a 1249URL outside the same CALLBACK mount area. User space on the connection is 1250arranged to be the size of the new protocol user space allocation as given in 1251the protocol struct. 1252 1253This allocation is only deleted / replaced when the connection accesses a 1254URL region with a different protocol (or the default protocols[0] if no 1255CALLBACK area matches it). 1256 1257This "binding connection to a protocol" lifecycle in managed by 1258`LWS_CALLBACK_HTTP_BIND_PROTOCOL` and `LWS_CALLBACK_HTTP_DROP_PROTOCOL`. 1259Because of HTTP/1.1 connection pipelining, one connection may perform 1260many transactions, each of which may map to different URLs and need 1261binding to different protocols. So these messages are used to 1262create the binding of the wsi to your protocol including any 1263allocations, and to destroy the binding, at which point you should 1264destroy any related allocations. 1265 1266@section BINDTODEV SO_BIND_TO_DEVICE 1267 1268The .bind_iface flag in the context / vhost creation struct lets you 1269declare that you want all traffic for listen and transport on that 1270vhost to be strictly bound to the network interface named in .iface. 1271 1272This Linux-only feature requires SO_BIND_TO_DEVICE, which in turn 1273requires CAP_NET_RAW capability... root has this capability. 1274 1275However this feature needs to apply the binding also to accepted 1276sockets during normal operation, which implies the server must run 1277the whole time as root. 1278 1279You can avoid this by using the Linux capabilities feature to have 1280the unprivileged user inherit just the CAP_NET_RAW capability. 1281 1282You can confirm this with the test server 1283 1284 1285``` 1286 $ sudo /usr/local/bin/libwebsockets-test-server -u agreen -i eno1 -k 1287``` 1288 1289The part that ensures the capability is inherited by the unprivileged 1290user is 1291 1292``` 1293#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) 1294 info.caps[0] = CAP_NET_RAW; 1295 info.count_caps = 1; 1296#endif 1297``` 1298 1299 1300@section dim Dimming webpage when connection lost 1301 1302The lws test plugins' html provides useful feedback on the webpage about if it 1303is still connected to the server, by greying out the page if not. You can 1304also add this to your own html easily 1305 1306 - include lws-common.js from your HEAD section 1307 1308 \<script src="/lws-common.js">\</script> 1309 1310 - dim the page during initialization, in a script section on your page 1311 1312 lws_gray_out(true,{'zindex':'499'}); 1313 1314 - in your ws onOpen(), remove the dimming 1315 1316 lws_gray_out(false); 1317 1318 - in your ws onClose(), reapply the dimming 1319 1320 lws_gray_out(true,{'zindex':'499'}); 1321 1322@section errstyle Styling http error pages 1323 1324In the code, http errors should be handled by `lws_return_http_status()`. 1325 1326There are basically two ways... the vhost can be told to redirect to an "error 1327page" URL in response to specifically a 404... this is controlled by the 1328context / vhost info struct (`struct lws_context_creation_info`) member 1329`.error_document_404`... if non-null the client is redirected to this string. 1330 1331If it wasn't redirected, then the response code html is synthesized containing 1332the user-selected text message and attempts to pull in `/error.css` for styling. 1333 1334If this file exists, it can be used to style the error page. See 1335https://libwebsockets.org/git/badrepo for an example of what can be done ( 1336and https://libwebsockets.org/error.css for the corresponding css). 1337 1338