mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
Fault injection
add lws_xos: xoshiro256 PRNG
This commit is contained in:
parent
33f5bf2e2d
commit
51490ae6e6
53 changed files with 1543 additions and 842 deletions
|
@ -117,6 +117,10 @@
|
|||
"cmake": "-DLWS_WITH_UDP=0",
|
||||
"platforms": "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc, freertos-linkit/arm32-m4-mt7697-usi/gcc, linux-ubuntu-2004/aarch64-a72-bcm2711-rpi4/gcc, w10/x86_64-amd/mingw32, w10/x86_64-amd/mingw64, netbsd/aarch64BE-bcm2837-a53/gcc, w10/x86_64-amd/wmbedtlsmsvc"
|
||||
},
|
||||
"fault-injection": {
|
||||
"cmake": "-DLWS_WITH_SYS_FAULT_INJECTION=1 -DLWS_WITH_MINIMAL_EXAMPLES=1",
|
||||
"platforms": "w10/x86_64-amd/msvc"
|
||||
},
|
||||
"esp32-heltec": {
|
||||
"cmake": "-DLWS_IPV6=0",
|
||||
"cpack": "esp-heltec-wb32",
|
||||
|
|
|
@ -1,40 +1,116 @@
|
|||
# `lws_fi` Fault Injection
|
||||
|
||||
To provide better quality there's a need to not just test the code paths for
|
||||
normal operation, but also that it acts correctly under various fault
|
||||
conditions that may be difficult to arrange at test-time.
|
||||
Most efforts during development go towards trying to make the system do what
|
||||
it is supposed to do during normal operation.
|
||||
|
||||
Code handling the failures may be anywhere including during early initialization
|
||||
or in user code before lws intialization.
|
||||
But to provide reliable quality there's a need to not just test the code paths
|
||||
for normal operation, but also to be able to easily confirm that they act
|
||||
correctly under various fault conditions that may be difficult to arrange at
|
||||
test-time. It's otherwise very easy for error conditions that are low
|
||||
probability to be overlooked and turn out to do the wrong thing, eg, try to
|
||||
clean up things they had not actually initialized, or forget to free things etc.
|
||||
|
||||
To help with this lws has `LWS_WITH_SYS_FAULT_INJECTION` build option that
|
||||
provides a simple but powerful api for fault injection in any lws or user code.
|
||||
Code handling the operational failures we want to check may be anywhere,
|
||||
including during early initialization or in user code before lws intialization.
|
||||
|
||||
To help with this lws has a `LWS_WITH_SYS_FAULT_INJECTION` build option that
|
||||
provides a simple but powerful api for targeted fault injection in any lws or
|
||||
user code, and provides a wide range of well-known internal faults inside lws
|
||||
you can trigger from outside.
|
||||
|
||||
## Fault contexts and faults
|
||||
|
||||
`lws_fi_t` objects represent a named fault injection rules, just in terms of
|
||||
whether and how often to inject the fault.
|
||||
The basic idea is objects in the user code can choose to initialize "fault
|
||||
contexts" inside objects, that list named, well-known "faults" that the code
|
||||
supoorts and that the user wants to inject.
|
||||
|
||||
`lws_fi_ctx_t` objects are linked-lists of `lws_fi_t` objects. When Fault
|
||||
Injection is enabled at build-time, the key system objects like the
|
||||
`lws_context`, `lws_vhost`, `wsi` and Secure Stream handles / SSPC handles
|
||||
contain their own `lws_fi_ctx_t` lists that may have any number of `lws_fi_t`
|
||||
added to them.
|
||||
Although these "fault contexts" can be embedded in objects directly at object
|
||||
creation time, eg, for lws in the lws_context creation info struct, or the
|
||||
client connection info struct, or Secure Stream info struct, it's usually
|
||||
inconvenient to pass the desired faults directly deep into the code and attach
|
||||
them at creation time. Eg, if you want to cause a fault in a wsi instantiated
|
||||
by a Secure Stream, that is internal lws code one step removed from the Secure
|
||||
Stream object creation making it difficult to arrange.
|
||||
|
||||
`lws_fi_ctx_t` objects are hierarchical, if a named rule is not found in, eg,
|
||||
a wsi Fault injection context, then the vhost and finally the lws_context Fault
|
||||
Injection contexts are searched for it before giving up. This allows for both
|
||||
global and individual overridden Fault Injection rules at each level.
|
||||
For that reason, faults have a targeted inheritance scheme using namespace
|
||||
paths, it's usually enough to just list the faults you want at context creation
|
||||
time and they will be filter down to the internal objects you want to target
|
||||
when they are created later.
|
||||
|
||||
## Integrating fault injection conditionals into code
|
||||

|
||||
|
||||
A simple api `lws_fi(fi_ctx, "name")` is provided that returns 0 if no fault to
|
||||
be injected, or 1 if the fault should be synthesized. If there is no rule
|
||||
matching "name", the answer is always to not inject a fault, ie, returns 0.
|
||||
A fault injection request is made in `lws_fi_t` objects, specifying the
|
||||
fault name and whether, and how often to inject the fault.
|
||||
|
||||
The "fault context" objects `lws_fi_ctx_t` embedded in the creation info
|
||||
structs are linked-lists of `lws_fi_t` objects. When Fault Injection is enabled
|
||||
at build-time, the key system objects like the `lws_context`, `lws_vhost`, `wsi`
|
||||
and Secure Stream handles / SSPC handles contain their own `lws_fi_ctx_t` lists
|
||||
that may have any number of `lws_fi_t` added to them.
|
||||
|
||||
When downstream objects are created, eg, when an lws_context creates a Secure
|
||||
Stream, in addition to using any faults provided directly in the SS info,
|
||||
the lws_context faults are consulted to see if any relate to that streamtype
|
||||
and should be applied.
|
||||
|
||||
Although faults can be added to objects at creation, it is far more convenient
|
||||
to just pass a list of faults you want into the lws_context and have the
|
||||
objects later match them using namespacing, described later.
|
||||
|
||||
## Integrating fault injection conditionals into code in private lws code
|
||||
|
||||
A simple query api `lws_fi(fi_ctx, "name")` is provided that returns 0 if no
|
||||
fault to be injected, or 1 if the fault should be synthesized. If there is no
|
||||
rule matching "name", the answer is always to not inject a fault, ie, returns 0.
|
||||
|
||||
Similarly for convenience if FAULT_INJECTION is disabled at build, the `lws_fi()`
|
||||
call always returns the constant `0`.
|
||||
|
||||
By default then just enabling Fault Injection at build does not have any impact
|
||||
on code operation since the user must first add the fault injection rules he
|
||||
wants.
|
||||
on code operation since the user must also add the fault injection rules he
|
||||
wants to the objects's Fault Injection context.
|
||||
|
||||
## Integrating fault injection conditionals into user code with public apis
|
||||
|
||||
These public apis query the fault context in a wsi, lws_context, ss handle, or
|
||||
sspc handle (client side of proxy) to find any matching rule, if so they return
|
||||
1 if the conditions (eg, probability) are met and the fault should be injected.
|
||||
|
||||
These allow user code to use the whole Fault Injection system without having to
|
||||
understand anything except the common object like a wsi they want to query and
|
||||
the name of the fault rule they are checking.
|
||||
|
||||
|FI context owner|Public API|
|
||||
|---|---|
|
||||
|lws_context|`int lws_fi_user_context_fi(struct lws_context *ctx, const char *rule)`|
|
||||
|wsi|`int lws_fi_user_wsi_fi(struct lws *wsi, const char *rule)`|
|
||||
|ss handle|`int lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *rule)`|
|
||||
|sspc handle|`int lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *rule)`|
|
||||
|
||||
For example, the minimal-http-client user code example contains this in its
|
||||
ESTABLISHED callback
|
||||
|
||||
```
|
||||
if (lws_fi_user_wsi_fi(wsi, "user_reject_at_est"))
|
||||
return -1;
|
||||
```
|
||||
|
||||
which can be triggered by running it with
|
||||
|
||||
`lws-minimal-http-client --fault-injection 'wsi/user_reject_at_est'`, causing
|
||||
|
||||
```
|
||||
...
|
||||
[2021/03/11 13:41:05:2769] U: Connected to 46.105.127.147, http response: 200
|
||||
[2021/03/11 13:41:05:2776] W: lws_fi: Injecting fault unk->user_reject_at_est
|
||||
[2021/03/11 13:41:05:2789] E: CLIENT_CONNECTION_ERROR: HS: disallowed at ESTABLISHED
|
||||
...
|
||||
```
|
||||
|
||||
When `LWS_WITH_SYS_FAULT_INJECTION` is disabled, these public apis become
|
||||
preprocessor defines to `(0)`, so the related code is removed by the compiler.
|
||||
|
||||
## Types of fault injection "when" strategy
|
||||
|
||||
The api keeps track of each time the context was asked and uses this information
|
||||
to drive the decision about when to say yes, according to the type of rule
|
||||
|
@ -44,49 +120,215 @@ to drive the decision about when to say yes, according to the type of rule
|
|||
|`LWSFI_ALWAYS`|Unconditionally inject the fault|
|
||||
|`LWSFI_DETERMINISTIC`|after `pre` times without the fault, the next `count` times exhibit the fault`|
|
||||
|`LWSFI_PROBABILISTIC`|exhibit a fault `pre` percentage of the time|
|
||||
|`LWSFI_PATTERN`|Reference `pre` bits pointed to by `pattern` and fault if the bit set|
|
||||
|`LWSFI_PATTERN`|Reference `pre` bits pointed to by `pattern` and fault if the bit set, pointing to static array|
|
||||
|`LWSFI_PATTERN_ALLOC`|Reference `pre` bits pointed to by `pattern` and fault if the bit set, pointing to allocated array, freed when fault goes out of scope|
|
||||
|
||||
Probabalistic choices are sourced from a PRNG with a seed set in the context
|
||||
creation info Fault Injection Context. By default the lws helper
|
||||
`lws_cmdline_option_handle_builtin()` sets this to the time in us, but it can
|
||||
be overridden using `--fault-seed <decimal>`, and the effective PRNG seed is
|
||||
logged when the commandline options are initially parsed.
|
||||
|
||||
## Addings Fault Injection Rules to `lws_fi_ctx_t`
|
||||
|
||||
User code should prepare a `lws_fi_ctx_t` cleared down to zero if necessary,
|
||||
and one of these, eg on the stack
|
||||
Typically the lws_context is used as the central, toplevel place to define
|
||||
faults. This is done by adding prepared `lws_fi_t` objects on the stack one by
|
||||
one to the context creation info struct's `.fic` member, using
|
||||
`lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);`, this will allocate and copy
|
||||
the provided `fi` into the allocation, and attach it to the `lws_fi_ctx_t` list.
|
||||
|
||||
```
|
||||
typedef struct lws_fi {
|
||||
const char *name;
|
||||
uint8_t *pattern;
|
||||
uint64_t pre__prob1;
|
||||
uint64_t count__prob2;
|
||||
char type; /* LWSFI_* */
|
||||
} lws_fi_t;
|
||||
```
|
||||
|
||||
and call `lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);`, this will
|
||||
allocate and copy the provided `fi` into the allocation, and attach it to
|
||||
the `lws_fi_ctx_t` list.
|
||||
|
||||
The creation info struct associated with the context, vhost, wsi or Secure
|
||||
Stream has a `*fi` pointer you can set to your `lws_fi_ctx_t`, when creating
|
||||
the object it will take ownership of any `lws_fi_t` you attached to it.
|
||||
|
||||
So the `lws_fi_ctx_t` and the `lws_fi_t` used as a template for adding the
|
||||
rules may be on the stack and safely and go out of scope after the object
|
||||
creation api is called. The `lws_fi_t` `name` is also copied into the
|
||||
allocation and does not need to continue to exist after it is added to the
|
||||
`lws_fi_ctx_t`. The only exception is the `pattern` member if used, the
|
||||
array pointed to is not copied and must exist for the lifetime of the rule.
|
||||
When the context (or other object using the same scheme) is created, it imports
|
||||
all the faults from the info structure `.fic` and takes ownership of them,
|
||||
leaving the info `.fic` empty and ready to go out of scope.
|
||||
|
||||
## Passing in fault injection rules
|
||||
|
||||
A key requirement is that Fault Injection rules must be availble to the code
|
||||
creating an object before the object has been created. This is why the user
|
||||
code prepares a temporary context listing his rules, and offers it as part of
|
||||
the creation info struct, rather than waiting for the object to be created and
|
||||
then attach Fault Injection rules... it's too late to test faults during the
|
||||
creation by then otherwise.
|
||||
code prepares a Fault Injection context listing his rules in the creation info
|
||||
struct, rather than waiting for the object to be created and then attach Fault
|
||||
Injection rules... it's too late then to test faults during the creation.
|
||||
|
||||
## Directly applying fault contexts
|
||||
|
||||
You can pass in a Fault Injection context prepared with lws_fi_t added to it
|
||||
when creating the following kinds of objects
|
||||
|
||||
|Object being created|info struct|Fault injection Context member|
|
||||
|---|---|---|
|
||||
|lws context|struct lws_context_creation_info|`fic`|
|
||||
|vhost|struct lws_context_creation_info|`fic`|
|
||||
|Secure Stream|struct lws_ss_info|`fic`|
|
||||
|client wsi|struct lws_client_connect_info|`fic`|
|
||||
|
||||
However typically the approach is just provide a list of faults at context
|
||||
creation time, and let the objects match and inherit using namespacing,
|
||||
described next.
|
||||
|
||||
## Using the namespace to target specific instances
|
||||
|
||||
Wsi client connection can directly have fault injection objects attached to it
|
||||
at client connection creation time.
|
||||
Lws objects created by the user can directly have a Fault Injection context
|
||||
attached to them at creation time, so the fault injection objects directly
|
||||
relate to the object.
|
||||
|
||||
But in other common scenarios, there is no direct visibility of the object that
|
||||
we want to trigger faults in, it may not exist until some time later. Eg, we
|
||||
want to trigger faults in the listen socket of a vhost. To allow this, the
|
||||
fault names can be structured with a /path/ type namespace so objects created
|
||||
later can inherit faults.
|
||||
|
||||
Notice that if you are directly creating the vhost, Secure Stream or wsi, you
|
||||
can directly attach the subrule yourself without the namespacing needed. The
|
||||
namespacing is used when you have access to a higher level object at creation-
|
||||
time, like the lws_context, and it will itself create the object you want to
|
||||
target without your having any direct access to it.
|
||||
|
||||
|namespace form|effect|
|
||||
|---|---|
|
||||
|**vh=myvhost/**subrule|subrule is inherited by the vhost named "myvhost" when it is created|
|
||||
|**vh/**subrule|subrule is inherited by any vhost when it is created|
|
||||
|**ss=mystream/**subrule|subrule is inherited by SS of streamtype "mystream" (also covers SSPC / proxy client)|
|
||||
|**ss/**subrule|subrule is inherited by all SS of any streamtype (also covers SSPC / proxy client)|
|
||||
|**wsi=myname/**subrule|subrule is inherited by client wsi created with `info->fi_wsi_name` "myname"|
|
||||
|**wsi/**subrule|subrule is inherited by any wsi|
|
||||
|
||||
Namespaces can be combined, for example `vh=myvhost/wsi/listenskt` will set the
|
||||
`listenskt` fault on wsi created by the server vhost "myvhost", ie, it will
|
||||
cause the listen socket for the vhost to error out on creation.
|
||||
|
||||
In the case of wsi migration when it's the network connection wsi on an h2
|
||||
connection that is migrated to be SID 1, the attached faults also migrate.
|
||||
|
||||
Here is which Fault Injection Contexts each type of object inherits matching
|
||||
Fault Injection rules from:
|
||||
|
||||
|Object type|Initialized with|Inherit matching faults from|
|
||||
|---|---|---|
|
||||
|context|`struct lws_context_creation_info` .fic|-|
|
||||
|vhost|`struct lws_context_creation_info` .fic|context FIC|
|
||||
|client wsi|`struct lws_client_connect_info` .fic|context FIC, vhost FIC|
|
||||
|ss / sspc|`lws_ss_info_t` .fic|context FIC|
|
||||
|ss / sspc wsi|-|context FIC, vhost FIC, ss / sspc .fic|
|
||||
|
||||
Since everything can be reached from the lws_context fault context, directly or
|
||||
by additional inheritence, and that's the most convenient to set from the
|
||||
outside, that's typically the original source of all injected faults.
|
||||
|
||||
## Integration with minimal examples
|
||||
|
||||
All the minimal examples that use the `lws_cmdline_option_handle_builtin()` api
|
||||
can take an additional `--fault-injection "...,..."` switch, which automatically
|
||||
parses the comma-separated list in the argument to add faults with the given
|
||||
name to the lws_context. For example,
|
||||
|
||||
`lws-minimal-http-client --fault-injection "wsi/dnsfail"`
|
||||
|
||||
will force all wsi dns lookups to fail for that run of the example.
|
||||
|
||||
### Specifying when to inject the fault
|
||||
|
||||
By default, if you just give the name part, if the namespace is absent or
|
||||
matches an object, the fault will be injected every time. It's also possible
|
||||
to make the fault inject itself at a random probability, or in a cyclic pattern,
|
||||
by giving additional information in brackets, eg
|
||||
|
||||
|Syntax|Meaning|
|
||||
|---|---|
|
||||
|`wsi/thefault`|Inject the fault every time|
|
||||
|`wsi/thefault(10%)`|Randomly inject the fault at 10% probability|
|
||||
|`wsi/thefault(.............X.X)`|Inject the fault on the 14th and 16th try, every 16 tries|
|
||||
|
||||
You must quote the strings containing these symbols, since they may otherwise be
|
||||
interpreted by your shell.
|
||||
|
||||
## Well-known fault names in lws
|
||||
|
||||
|Scope|Namespc|Name|Fault effect|
|
||||
|---|---|---|---|
|
||||
|context||`ctx_createfail1`|Fail context creation immediately at entry|
|
||||
|context||`ctx_createfail_plugin_init`|Fail context creation as if a plugin init failed (if plugins enabled)|
|
||||
|context||`ctx_createfail_evlib_plugin`|Fail context creation due to event lib plugin failed init (if evlib plugins enabled)|
|
||||
|context||`ctx_createfail_evlib_sel`|Fail context creation due to unable to select event lib|
|
||||
|context||`ctx_createfail_oom_ctx`|Fail context creation due to OOM on context object|
|
||||
|context||`ctx_createfail_privdrop`|Fail context creation due to failure dropping privileges|
|
||||
|context||`ctx_createfail_maxfds`|Fail context creation due to unable to determine process fd limit|
|
||||
|context||`ctx_createfail_oom_fds`|Fail context creation due to OOM on fds table|
|
||||
|context||`ctx_createfail_plat_init`|Fail context creation due to platform init failed|
|
||||
|context||`ctx_createfail_evlib_init`|Fail context creation due to event lib init failed|
|
||||
|context||`ctx_createfail_evlib_pt`|Fail context creation due to event lib pt init failed|
|
||||
|context||`ctx_createfail_sys_vh`|Fail context creation due to system vhost creation failed|
|
||||
|context||`ctx_createfail_sys_vh_init`|Fail context creaton due to system vhost init failed|
|
||||
|context||`ctx_createfail_def_vh`|Fail context creation due to default vhost creation failed|
|
||||
|context||`ctx_createfail_ss_pol1`|Fail context creation due to ss policy parse start failed (if policy enabled)|
|
||||
|context||`ctx_createfail_ss_pol2`|Fail context creation due to ss policy parse failed (if policy enabled)|
|
||||
|context||`ctx_createfail_ss_pol3`|Fail context creation due to ss policy set failed (if policy enabled)|
|
||||
|vhost|`vh`|`vh_create_oom`|Fail vh creation on vh object alloc OOM|
|
||||
|vhost|`vh`|`vh_create_pcols_oom`|Fail vh creation at protocols alloc OOM|
|
||||
|vhost|`vh`|`vh_create_access_log_open_fail`|Fail vh creation due to unable to open access log (LWS_WITH_ACCESS_LOG)|
|
||||
|vhost|`vh`|`vh_create_ssl_srv`|Fail server ssl_ctx init|
|
||||
|vhost|`vh`|`vh_create_ssl_cli`|Fail client ssl_ctx init|
|
||||
|vhost|`vh`|`vh_create_srv_init`|Fail server init|
|
||||
|vhost|`vh`|`vh_create_protocol_init`|Fail late protocol init (for late vhost creation)|
|
||||
|srv vhost|`vh=xxx/wsi`|`listenskt`|Causes `socket()` allocation for vhost listen socket to fail|
|
||||
|cli wsi|`wsi`|`dnsfail`|Sync: `getaddrinfo()` is not called and a EAI_FAIL return synthesized, Async: request not started and immediate fail synthesized|
|
||||
|cli wsi|`wsi`|`sendfail`|Attempts to send data on the wsi socket fail|
|
||||
|cli wsi|`wsi`|`connfail`|Attempts to connect on the wsi socket fail|
|
||||
|cli wsi|`wsi`|`createfail`|Creating the client wsi itself fails|
|
||||
|udp wsi|`wsi`|`udp_rx_loss`|Drop UDP RX that was actually received, useful with probabalistic mode|
|
||||
|udp wsi|`wsi`|`udp_tx_loss`|Drop UDP TX so that it's not actually sent, useful with probabalistic mode|
|
||||
|srv ss|`ss`|`ss_srv_vh_fail`|Secure Streams Server vhost creation forced to fail|
|
||||
|cli ss|`ss`|`ss_no_streamtype_policy`|The policy for the streamtype is made to seem as if it is missing|
|
||||
|sspc|`ss`|`sspc_fail_on_linkup`|Reject the connection to the proxy when we hear it has succeeded, it will provoke endless retries|
|
||||
|sspc|`ss`|`sspc_fake_rxparse_disconnect_me`|Force client-proxy link parse to seem to ask to be disconnected, it will provoke endless retries|
|
||||
|sspc|`ss`|`sspc_fake_rxparse_destroy_me`|Force client-proxy link parse to seem to ask to destroy the SS, it will destroy the SS cleanly|
|
||||
|sspc|`ss`|`sspc_link_write_fail`|Force write on the link to fail, it will provoke endless retries|
|
||||
|sspc|`ss`|`sspc_create_oom`|Cause the sspc handle allocation to fail as if OOM at creation time|
|
||||
|sspc|`ss`|`sspc_fail_metadata_set`|Cause the metadata allocation to fail|
|
||||
|sspc|`ss`|`sspc_rx_fake_destroy_me`|Make it seem that client's user code *rx() returned DESTROY_ME|
|
||||
|sspc|`ss`|`sspc_rx_metadata_oom`|Cause metadata from proxy allocation to fail|
|
||||
|ssproxy|`ss`|`ssproxy_dsh_create_oom`|Cause proxy's creation of DSH to fail|
|
||||
|ssproxy|`ss`|`ssproxy_dsh_rx_queue_oom`|Cause proxy's allocation in the onward SS->P[->C] DSH rx direction to fail as if OOM, this causes the onward connection to disconnect|
|
||||
|ssproxy|`wsi`|`ssproxy_client_adopt_oom`|Cause proxy to be unable to allocate for new client - proxy link connection object|
|
||||
|ssproxy|`wsi`|`ssproxy_client_write_fail`|Cause proxy write to client to fail|
|
||||
|ssproxy|`wsi`|`sspc_dsh_ss2p_oom`|Cause ss->proxy dsh allocation to fail|
|
||||
|ssproxy|`ss`|`ssproxy_onward_conn_fail`|Act as if proxy onward client connection failed immediately|
|
||||
|ssproxy|`ss`|`ssproxy_dsh_c2p_pay_oom`|Cause proxy's DSH alloc for C->P payload to fail|
|
||||
|
||||
|
||||
## Well-known namespace targets
|
||||
|
||||
Namespaces can be used to target these more precisely, for example even though
|
||||
we are only passing the faults we want inject at the lws_context, we can use
|
||||
the namespace "paths" to target only the wsis created by other things.
|
||||
|
||||
To target wsis from SS-based connections, you can use `ss=stream_type_name/`,
|
||||
eg for captive portal detection, to have it unable to find its policy entry:
|
||||
|
||||
`ss=captive_portal_detect/ss_no_streamtype_policy` (disables CPD from operating)
|
||||
|
||||
...to force it to fail to resolve the server DNS:
|
||||
|
||||
`ss=captive_portal_detect/wsi/dnsfail` (this makes CPD feel there is no internet)
|
||||
|
||||
...to target the connection part of the captive portal testing instead:
|
||||
|
||||
`ss=captive_portal_detect/wsi/connfail` (this also makes CPD feel there is no internet)
|
||||
|
||||
### Well-known internal wsi type names
|
||||
|
||||
Wsi created for internal features like Async DNS processing can also be targeted
|
||||
|
||||
|wsi target|Meaning|
|
||||
|---|---|
|
||||
|`wsi=asyncdns/`|UDP wsi used by lws Async DNS support to talk to DNS servers|
|
||||
|`wsi=dhcpc/`|UDP wsi used by lws DHCP Client|
|
||||
|`wsi=ntpclient/`|UDP wsi used by lws NTP Client|
|
||||
|
||||
For example, passing in at lws_context level `wsi=asyncdns/udp_tx_loss`
|
||||
will force async dns to be unable to resolve anything since its UDP tx is
|
||||
being suppressed.
|
||||
|
||||
At client connection creation time, user code can also specify their own names
|
||||
to match on these `wsi=xxx/` namespace parts, so the faults only apply to
|
||||
specific wsi they are creating themselves later. This is done by setting the
|
||||
client creation info struct `.fi_wsi_name` to the string "xxx".
|
||||
|
|
|
@ -44,7 +44,7 @@ In the callback, it should simply call `lws_callback_on_writable()` for the udp
|
|||
|
||||
## Simulating packetloss
|
||||
|
||||
lws now allows you to set the amount of simulated packetloss on udp rx and tx in
|
||||
the context creation info struct, using `.udp_loss_sim_tx_pc` and `.udp_loss_sim_rx_pc`,
|
||||
the values are percentages between 0 and 100. 0, the default, means no packetloss.
|
||||
|
||||
You can simulate udp packetloss at tx and rx by using the Fault Injection apis
|
||||
with the well-known fault names "udp_tx_loss" and "udp_rx_loss", typically
|
||||
with the probabilistic setting, in commandline format something like
|
||||
`--fault-injection "wsi/udp_tx_loss(10%)"`
|
||||
|
|
BIN
doc-assets/fault-injection.png
Normal file
BIN
doc-assets/fault-injection.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 240 KiB |
|
@ -152,6 +152,7 @@ typedef struct lws_adopt_desc {
|
|||
const char *vh_prot_name; /**< NULL or vh protocol name to bind raw connection to */
|
||||
struct lws *parent; /**< NULL or struct lws to attach new_wsi to as a child */
|
||||
void *opaque; /**< opaque pointer to set on created wsi */
|
||||
const char *fi_wsi_name; /**< NULL, or Fault Injection inheritence filter for wsi=string/ context faults */
|
||||
} lws_adopt_desc_t;
|
||||
|
||||
/**
|
||||
|
@ -249,6 +250,11 @@ lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
|
|||
* \param parent_wsi: NULL or parent wsi new wsi will be a child of
|
||||
* \param opaque: set created wsi opaque ptr to this
|
||||
* \param retry_policy: NULL for vhost default policy else wsi specific policy
|
||||
* \param fi_wsi_name: NULL, or string to inherit Fault Injection rules in
|
||||
* form "wsi=string/rule". "wsi/rule" faults will be
|
||||
* automatically applied as well. It's done at creation
|
||||
* time so the rules can, eg, inject faults related to
|
||||
* creation.
|
||||
*
|
||||
* Either returns new wsi bound to accept_fd, or closes accept_fd and
|
||||
* returns NULL, having cleaned up any new wsi pieces.
|
||||
|
@ -257,7 +263,7 @@ LWS_VISIBLE LWS_EXTERN struct lws *
|
|||
lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
||||
int flags, const char *protocol_name, const char *ifname,
|
||||
struct lws *parent_wsi, void *opaque,
|
||||
const lws_retry_bo_t *retry_policy);
|
||||
const lws_retry_bo_t *retry_policy, const char *fi_wsi_name);
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -206,10 +206,15 @@ struct lws_client_connect_info {
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t *fi;
|
||||
lws_fi_ctx_t fic;
|
||||
/**< Attach external Fault Injection context to the client wsi,
|
||||
* hierarchy is wsi -> vhost -> context */
|
||||
#endif
|
||||
/* for convenience, available when FI disabled in build */
|
||||
const char *fi_wsi_name;
|
||||
/**< specific Fault Injection namespace name for wsi created for this
|
||||
* connection, allows targeting by "wsi=XXX/..." if you give XXX here.
|
||||
*/
|
||||
|
||||
uint16_t keep_warm_secs;
|
||||
/**< 0 means 5s. If the client connection to the endpoint becomes idle,
|
||||
|
|
|
@ -810,17 +810,9 @@ struct lws_context_creation_info {
|
|||
*/
|
||||
|
||||
#endif /* PEER_LIMITS */
|
||||
#if defined(LWS_WITH_UDP)
|
||||
uint8_t udp_loss_sim_tx_pc;
|
||||
/**< CONTEXT: percentage of udp writes we could have performed
|
||||
* to instead not do, in order to simulate and test udp retry flow */
|
||||
uint8_t udp_loss_sim_rx_pc;
|
||||
/**< CONTEXT: percentage of udp reads we actually received
|
||||
* to make disappear, in order to simulate and test udp retry flow */
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t *fi;
|
||||
lws_fi_ctx_t fic;
|
||||
/**< CONTEXT | VHOST: attach external Fault Injection context to the
|
||||
* lws_context or vhost. If creating the context + default vhost in
|
||||
* one step, only the context binds to \p fi. When creating a vhost
|
||||
|
|
|
@ -24,13 +24,54 @@
|
|||
* Fault injection api if built with LWS_WITH_SYS_FAULT_INJECTION
|
||||
*/
|
||||
|
||||
typedef struct lws_xos {
|
||||
uint64_t s[4];
|
||||
} lws_xos_t;
|
||||
|
||||
/**
|
||||
* lws_xos_init() - seed xoshiro256 PRNG
|
||||
*
|
||||
* \param xos: the prng state object to initialize
|
||||
* \param seed: the 64-bit seed
|
||||
*
|
||||
* Initialize PRNG \xos with the starting state represented by \p seed
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_xos_init(struct lws_xos *xos, uint64_t seed);
|
||||
|
||||
/**
|
||||
* lws_xos() - get next xoshiro256 PRNG result and update state
|
||||
*
|
||||
* \param xos: the PRNG state to use
|
||||
*
|
||||
* Returns next 64-bit PRNG result. These are cheap to get,
|
||||
* quite a white noise sequence, and completely deterministic
|
||||
* according to the seed it was initialized with.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN uint64_t LWS_WARN_UNUSED_RESULT
|
||||
lws_xos(struct lws_xos *xos);
|
||||
|
||||
/**
|
||||
* lws_xos_percent() - return 1 a given percent of the time on average
|
||||
*
|
||||
* \param xos: the PRNG state to use
|
||||
* \param percent: chance in 100 of returning 1
|
||||
*
|
||||
* Returns 1 if next random % 100 is < \p percent, such that
|
||||
* 100 always returns 1, 0 never returns 1, and the chance linearly scales
|
||||
* inbetween
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_xos_percent(struct lws_xos *xos, int percent);
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
|
||||
enum {
|
||||
LWSFI_ALWAYS,
|
||||
LWSFI_DETERMINISTIC, /* do .count injections after .pre then stop */
|
||||
LWSFI_PROBABILISTIC, /* .prob1 / .prob2 chance of injection */
|
||||
LWSFI_PROBABILISTIC, /* .pre % chance of injection */
|
||||
LWSFI_PATTERN, /* use .count bits in .pattern after .pre */
|
||||
LWSFI_PATTERN_ALLOC, /* as _PATTERN, but .pattern is malloc'd */
|
||||
};
|
||||
|
||||
typedef struct lws_fi {
|
||||
|
@ -44,8 +85,8 @@ typedef struct lws_fi {
|
|||
|
||||
typedef struct lws_fi_ctx {
|
||||
lws_dll2_owner_t fi_owner;
|
||||
struct lws_xos xos;
|
||||
const char *name;
|
||||
struct lws_fi_ctx *parent;
|
||||
} lws_fi_ctx_t;
|
||||
|
||||
/**
|
||||
|
@ -65,7 +106,7 @@ typedef struct lws_fi_ctx {
|
|||
* If LWS_WITH_SYS_FAULT_INJECTION is not defined, then this always return 0.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_fi(lws_fi_ctx_t *fic, const char *fi_name);
|
||||
lws_fi(const lws_fi_ctx_t *fic, const char *fi_name);
|
||||
|
||||
/**
|
||||
* lws_fi_add() - add an allocated copy of fault injection to a context
|
||||
|
@ -74,7 +115,7 @@ lws_fi(lws_fi_ctx_t *fic, const char *fi_name);
|
|||
* \param fi: the fault injection details
|
||||
*
|
||||
* This allocates a copy of \p fi and attaches it to the fault injection context
|
||||
* \p fic.
|
||||
* \p fic. \p fi can go out of scope after this safely.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);
|
||||
|
@ -91,6 +132,35 @@ lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);
|
|||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_fi_remove(lws_fi_ctx_t *fic, const char *name);
|
||||
|
||||
/**
|
||||
* lws_fi_import() - transfers all the faults from one context to another
|
||||
*
|
||||
* \param fic_dest: the fault context to receive the faults
|
||||
* \param fic_src: the fault context that will be emptied out into \p fic_dest
|
||||
*
|
||||
* This is used to initialize created object fault injection contexts from
|
||||
* the caller.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_fi_import(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src);
|
||||
|
||||
/**
|
||||
* lws_fi_inherit_copy() - attach copies of matching fault injection objects to dest
|
||||
*
|
||||
* \param fic_dest: destination Fault Injection context
|
||||
* \param fic_src: parent fault context that may contain matching rules
|
||||
* \param scope: the name of the path match required, eg, "vh"
|
||||
* \param value: the dynamic name of our match, eg, "myvhost"
|
||||
*
|
||||
* If called with scope "vh" and value "myvhost", then matches faults starting
|
||||
* "vh=myvhost/", strips that part of the name if it matches and makes a copy
|
||||
* of the rule with the modified name attached to the destination Fault Injection
|
||||
* context.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_fi_inherit_copy(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src,
|
||||
const char *scope, const char *value);
|
||||
|
||||
/**
|
||||
* lws_fi_destroy() - removes all allocated fault injection entries
|
||||
*
|
||||
|
@ -101,7 +171,44 @@ lws_fi_remove(lws_fi_ctx_t *fic, const char *name);
|
|||
* not usually directly allocated.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_fi_destroy(lws_fi_ctx_t *fic);
|
||||
lws_fi_destroy(const lws_fi_ctx_t *fic);
|
||||
|
||||
/**
|
||||
* lws_fi_deserialize() - adds fault in string form to Fault Injection Context
|
||||
*
|
||||
* \p fic: the fault injection context
|
||||
* \p sers: the string serializing the desired fault details
|
||||
*
|
||||
* This turns a string like "ss=captive_portal_detect/wsi/dnsfail(10%)" into
|
||||
* a fault injection struct added to the fault injection context \p fic
|
||||
*
|
||||
* You can prepare the context creation info .fic with these before creating
|
||||
* the context, and use namespace paths on those to target other objects.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_fi_deserialize(lws_fi_ctx_t *fic, const char *sers);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
_lws_fi_user_wsi_fi(struct lws *wsi, const char *name);
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
_lws_fi_user_context_fi(struct lws_context *ctx, const char *name);
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
struct lws_ss_handle;
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
_lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *name);
|
||||
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
|
||||
struct lws_sspc_handle;
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
_lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *name);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define lws_fi_user_wsi_fi(_wsi, _name) _lws_fi_user_wsi_fi(_wsi, _name)
|
||||
#define lws_fi_user_context_fi(_ctx, _name) _lws_fi_user_context_fi(_ctx, _name)
|
||||
#define lws_fi_user_ss_fi(_h, _name) _lws_fi_user_ss_fi(_h, _name)
|
||||
#define lws_fi_user_sspc_fi(_h, _name) _lws_fi_user_sspc_fi(_h, _name)
|
||||
|
||||
#else
|
||||
|
||||
|
@ -111,5 +218,12 @@ lws_fi_destroy(lws_fi_ctx_t *fic);
|
|||
*/
|
||||
|
||||
#define lws_fi(_fi_name, _fic) (0)
|
||||
#define lws_fi_destroy(_x)
|
||||
#define lws_fi_inherit_copy(_a, _b, _c, _d)
|
||||
#define lws_fi_deserialize(_x, _y)
|
||||
#define lws_fi_user_wsi_fi(_wsi, _name) (0)
|
||||
#define lws_fi_user_context_fi(_wsi, _name) (0)
|
||||
#define lws_fi_user_ss_fi(_h, _name) (0)
|
||||
#define lws_fi_user_sspc_fi(_h, _name) (0)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#define lws_ss_change_handlers lws_sspc_change_handlers
|
||||
#define lws_smd_ss_rx_forward lws_smd_sspc_rx_forward
|
||||
#define lws_ss_tag lws_sspc_tag
|
||||
#define _lws_fi_user_ss_fi _lws_fi_user_sspc_fi
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -354,7 +354,7 @@ typedef struct lws_ss_info {
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t *fi;
|
||||
lws_fi_ctx_t fic;
|
||||
/**< Attach external Fault Injection context to the stream, hierarchy
|
||||
* is ss->context */
|
||||
#endif
|
||||
|
|
|
@ -115,7 +115,7 @@ lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi, const char *de
|
|||
static struct lws *
|
||||
lws_adopt_descriptor_vhost1(struct lws_vhost *vh, lws_adoption_type type,
|
||||
const char *vh_prot_name, struct lws *parent,
|
||||
void *opaque)
|
||||
void *opaque, const char *fi_wsi_name)
|
||||
{
|
||||
struct lws_context *context = vh->context;
|
||||
struct lws_context_per_thread *pt;
|
||||
|
@ -139,6 +139,15 @@ lws_adopt_descriptor_vhost1(struct lws_vhost *vh, lws_adoption_type type,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* bring in specific fault injection rules early */
|
||||
lws_fi_inherit_copy(&new_wsi->fic, &context->fic, "wsi", fi_wsi_name);
|
||||
|
||||
if (lws_fi(&new_wsi->fic, "createfail")) {
|
||||
lws_fi_destroy(&new_wsi->fic);
|
||||
lws_context_unlock(vh->context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_wsi->a.opaque_user_data = opaque;
|
||||
|
||||
pt = &context->pt[(int)new_wsi->tsi];
|
||||
|
@ -201,6 +210,8 @@ bail:
|
|||
if (new_wsi->user_space)
|
||||
lws_free(new_wsi->user_space);
|
||||
|
||||
lws_fi_destroy(&new_wsi->fic);
|
||||
|
||||
lws_vhost_unbind_wsi(new_wsi);
|
||||
|
||||
lws_free(new_wsi);
|
||||
|
@ -509,7 +520,7 @@ lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info)
|
|||
|
||||
new_wsi = lws_adopt_descriptor_vhost1(info->vh, info->type,
|
||||
info->vh_prot_name, info->parent,
|
||||
info->opaque);
|
||||
info->opaque, info->fi_wsi_name);
|
||||
if (!new_wsi) {
|
||||
if (info->type & LWS_ADOPT_SOCKET)
|
||||
compatible_close(info->fd.sockfd);
|
||||
|
@ -772,7 +783,7 @@ struct lws *
|
|||
lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
||||
int flags, const char *protocol_name, const char *ifname,
|
||||
struct lws *parent_wsi, void *opaque,
|
||||
const lws_retry_bo_t *retry_policy)
|
||||
const lws_retry_bo_t *retry_policy, const char *fi_wsi_name)
|
||||
{
|
||||
#if !defined(LWS_PLAT_OPTEE)
|
||||
struct lws *wsi;
|
||||
|
@ -782,8 +793,10 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
|||
|
||||
/* create the logical wsi without any valid fd */
|
||||
|
||||
wsi = lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_SOCKET | LWS_ADOPT_RAW_SOCKET_UDP,
|
||||
protocol_name, parent_wsi, opaque);
|
||||
wsi = lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_SOCKET |
|
||||
LWS_ADOPT_RAW_SOCKET_UDP,
|
||||
protocol_name, parent_wsi, opaque,
|
||||
fi_wsi_name);
|
||||
if (!wsi) {
|
||||
lwsl_err("%s: udp wsi creation failed\n", __func__);
|
||||
goto bail;
|
||||
|
|
|
@ -86,7 +86,7 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
struct lws *wsi, *safe = NULL;
|
||||
const struct lws_protocols *p;
|
||||
const char *cisin[CIS_COUNT];
|
||||
struct lws_vhost *vh;
|
||||
struct lws_vhost *vh, *v;
|
||||
int
|
||||
#if LWS_MAX_SMP > 1
|
||||
tid = 0,
|
||||
|
@ -151,15 +151,41 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
/* any of these imply we are a client wsi bound to an SS, which
|
||||
* implies our opaque user ptr is the ss (or sspc if PROXY_LINK) handle
|
||||
*/
|
||||
wsi->for_ss = !!(i->ssl_connection & (LCCSCF_SECSTREAM_CLIENT | LCCSCF_SECSTREAM_PROXY_LINK | LCCSCF_SECSTREAM_PROXY_ONWARD));
|
||||
wsi->client_bound_sspc = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK); /* so wsi close understands need to remove sspc ptr to wsi */
|
||||
wsi->client_proxy_onward = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_ONWARD);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
wsi->fi.name = "wsi";
|
||||
wsi->fi.parent = &vh->fi;
|
||||
if (i->fi)
|
||||
wsi->fic.name = "wsi";
|
||||
if (i->fic.fi_owner.count)
|
||||
/*
|
||||
* This moves all the lws_fi_t from info->fi to the vhost fi,
|
||||
* This moves all the lws_fi_t from i->fi to the vhost fi,
|
||||
* leaving it empty
|
||||
*/
|
||||
lws_fi_import(&wsi->fi, i->fi);
|
||||
lws_fi_import(&wsi->fic, &i->fic);
|
||||
|
||||
lws_fi_inherit_copy(&wsi->fic, &i->context->fic, "wsi", i->fi_wsi_name);
|
||||
|
||||
if (lws_fi(&wsi->fic, "createfail"))
|
||||
goto bail;
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
|
||||
if (wsi->client_bound_sspc) {
|
||||
lws_sspc_handle_t *fih = (lws_sspc_handle_t *)i->opaque_user_data;
|
||||
lws_fi_inherit_copy(&wsi->fic, &fih->fic, "wsi", NULL);
|
||||
}
|
||||
#endif
|
||||
if (wsi->for_ss) {
|
||||
lws_ss_handle_t *fih = (lws_ss_handle_t *)i->opaque_user_data;
|
||||
lws_fi_inherit_copy(&wsi->fic, &fih->fic, "wsi", NULL);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -187,7 +213,7 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
wsi->conn_validity_wakesuspend = 1;
|
||||
|
||||
if (!i->vhost) {
|
||||
struct lws_vhost *v = i->context->vhost_list;
|
||||
v = i->context->vhost_list;
|
||||
|
||||
if (!v) { /* coverity */
|
||||
lwsl_err("%s: no vhost\n", __func__);
|
||||
|
@ -195,9 +221,15 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
}
|
||||
if (!strcmp(v->name, "system"))
|
||||
v = v->vhost_next;
|
||||
lws_vhost_bind_wsi(v, wsi);
|
||||
} else
|
||||
lws_vhost_bind_wsi(i->vhost, wsi);
|
||||
v = i->vhost;
|
||||
|
||||
lws_vhost_bind_wsi(v, wsi);
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
/* additionally inerit from vhost we bound to */
|
||||
lws_fi_inherit_copy(&wsi->fic, &v->fic, "wsi", i->fi_wsi_name);
|
||||
#endif
|
||||
|
||||
if (!wsi->a.vhost) {
|
||||
lwsl_err("%s: No vhost in the context\n", __func__);
|
||||
|
@ -332,12 +364,6 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
i->opaque_user_data;
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
/* any of these imply we are a client wsi bound to an SS, which
|
||||
* implies our opaque user ptr is the ss (or sspc if PROXY_LINK) handle
|
||||
*/
|
||||
wsi->for_ss = !!(i->ssl_connection & (LCCSCF_SECSTREAM_CLIENT | LCCSCF_SECSTREAM_PROXY_LINK | LCCSCF_SECSTREAM_PROXY_ONWARD));
|
||||
wsi->client_bound_sspc = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK); /* so wsi close understands need to remove sspc ptr to wsi */
|
||||
wsi->client_proxy_onward = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_ONWARD);
|
||||
|
||||
if (wsi->for_ss) {
|
||||
/* it's related to ss... the options are
|
||||
|
@ -515,6 +541,7 @@ bail1:
|
|||
lws_free_set_NULL(wsi->stash);
|
||||
|
||||
bail:
|
||||
lws_fi_destroy(&wsi->fic);
|
||||
lws_free(wsi);
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
bail2:
|
||||
|
|
|
@ -64,7 +64,10 @@ lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)
|
|||
#endif
|
||||
|
||||
wsi->dns_reachability = 0;
|
||||
n = getaddrinfo(ads, NULL, &hints, result);
|
||||
if (lws_fi(&wsi->fic, "dnsfail"))
|
||||
n = EAI_FAIL;
|
||||
else
|
||||
n = getaddrinfo(ads, NULL, &hints, result);
|
||||
|
||||
#if defined(LWS_WITH_CONMON)
|
||||
wsi->conmon.ciu_dns = (lws_conmon_interval_us_t)
|
||||
|
@ -99,7 +102,7 @@ lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)
|
|||
lws_snprintf(buckname, sizeof(buckname), "dns=\"unreachable %d\"", n);
|
||||
lws_metrics_hist_bump_priv_wsi(wsi, mth_conn_failures, buckname);
|
||||
#endif
|
||||
lwsl_notice("%s: asking to recheck CPD in 1s\n", __func__);
|
||||
lwsl_debug("%s: asking to recheck CPD in 1s\n", __func__);
|
||||
lws_system_cpd_start_defer(wsi->a.context, LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
|
@ -340,7 +343,10 @@ solo:
|
|||
#else
|
||||
/* this is either FAILED, CONTINUING, or already called connect_4 */
|
||||
|
||||
n = lws_async_dns_query(wsi->a.context, wsi->tsi, ads,
|
||||
if (lws_fi(&wsi->fic, "dnsfail"))
|
||||
return lws_client_connect_3_connect(wsi, NULL, NULL, -4, NULL);
|
||||
else
|
||||
n = lws_async_dns_query(wsi->a.context, wsi->tsi, ads,
|
||||
LWS_ADNS_RECORD_A, lws_client_connect_3_connect,
|
||||
wsi, NULL);
|
||||
|
||||
|
|
|
@ -151,6 +151,9 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads,
|
|||
lws_dns_sort_t *curr;
|
||||
ssize_t plen = 0;
|
||||
lws_dll2_t *d;
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
int cfail;
|
||||
#endif
|
||||
int m;
|
||||
|
||||
/*
|
||||
|
@ -433,7 +436,14 @@ ads_known:
|
|||
#endif
|
||||
|
||||
wsi->socket_is_permanently_unusable = 0;
|
||||
m = connect(wsi->desc.sockfd, (const struct sockaddr *)psa, (unsigned int)n);
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
cfail = lws_fi(&wsi->fic, "connfail");
|
||||
if (cfail)
|
||||
m = -1;
|
||||
else
|
||||
#endif
|
||||
m = connect(wsi->desc.sockfd, (const struct sockaddr *)psa, (unsigned int)n);
|
||||
|
||||
#if defined(LWS_WITH_CONMON)
|
||||
wsi->conmon_datum = lws_now_usecs();
|
||||
|
@ -450,6 +460,12 @@ ads_known:
|
|||
|
||||
int errno_copy = LWS_ERRNO;
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
if (cfail)
|
||||
/* fake an abnormal, fatal situation */
|
||||
errno_copy = 999;
|
||||
#endif
|
||||
|
||||
lwsl_debug("%s: connect: errno: %d\n", __func__, errno_copy);
|
||||
|
||||
if (errno_copy &&
|
||||
|
@ -481,10 +497,10 @@ ads_known:
|
|||
|
||||
lws_sa46_write_numeric_address(&wsi->sa46_peer, nads,
|
||||
sizeof(nads));
|
||||
lwsl_info("%s: Connect failed: %s port %d\n", __func__,
|
||||
nads, port);
|
||||
|
||||
wsi->sa46_peer.sa4.sin_family = 0;
|
||||
lwsl_info("%s: Connect failed: %s port %d (errno %d)\n",
|
||||
__func__, nads, port, errno_copy);
|
||||
#if defined(LWS_WITH_UNIX_SOCK)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -831,7 +831,7 @@ __lws_close_free_wsi_final(struct lws *wsi)
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_destroy(&wsi->fi);
|
||||
lws_fi_destroy(&wsi->fic);
|
||||
#endif
|
||||
|
||||
__lws_wsi_remove_from_sul(wsi);
|
||||
|
|
|
@ -114,7 +114,11 @@ lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
|
|||
|
||||
/* nope, send it on the socket directly */
|
||||
|
||||
m = (unsigned int)lws_ssl_capable_write(wsi, buf, n);
|
||||
if (lws_fi(&wsi->fic, "sendfail"))
|
||||
m = (unsigned int)LWS_SSL_CAPABLE_ERROR;
|
||||
else
|
||||
m = (unsigned int)lws_ssl_capable_write(wsi, buf, n);
|
||||
|
||||
lwsl_info("%s: ssl_capable_write (%d) says %d\n", __func__, n, m);
|
||||
|
||||
/* something got written, it can have been truncated now */
|
||||
|
@ -329,20 +333,11 @@ lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, size_t len)
|
|||
|
||||
#if defined(LWS_WITH_UDP)
|
||||
if (lws_wsi_is_udp(wsi)) {
|
||||
if (wsi->a.context->udp_loss_sim_tx_pc) {
|
||||
uint16_t u16;
|
||||
/*
|
||||
* We should randomly drop some of these
|
||||
*/
|
||||
|
||||
if (lws_get_random(wsi->a.context, &u16, 2) == 2 &&
|
||||
((u16 * 100) / 0xffff) <=
|
||||
wsi->a.context->udp_loss_sim_tx_pc) {
|
||||
lwsl_warn("%s: dropping udp tx\n", __func__);
|
||||
/* pretend it was sent */
|
||||
n = (int)(ssize_t)len;
|
||||
goto post_send;
|
||||
}
|
||||
if (lws_fi(&wsi->fic, "udp_tx_loss")) {
|
||||
/* pretend it was sent */
|
||||
n = (int)(ssize_t)len;
|
||||
goto post_send;
|
||||
}
|
||||
|
||||
if (lws_has_buffered_out(wsi))
|
||||
|
|
|
@ -469,7 +469,7 @@ struct lws_vhost {
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t fi;
|
||||
lws_fi_ctx_t fic;
|
||||
/**< Fault Injection ctx for the vhost, hierarchy vhost->context */
|
||||
#endif
|
||||
|
||||
|
@ -693,7 +693,7 @@ struct lws {
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t fi;
|
||||
lws_fi_ctx_t fic;
|
||||
/**< Fault Injection ctx for the wsi, hierarchy wsi->vhost->context */
|
||||
#endif
|
||||
|
||||
|
|
|
@ -159,9 +159,14 @@ _lws_route_remove(struct lws_context_per_thread *pt, lws_route_t *robj, int flag
|
|||
void
|
||||
_lws_route_table_empty(struct lws_context_per_thread *pt)
|
||||
{
|
||||
|
||||
if (!pt->context)
|
||||
return;
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
|
||||
lws_dll2_get_head(&pt->context->routing_table)) {
|
||||
lws_route_t *rou = lws_container_of(d, lws_route_t, list);
|
||||
|
||||
lws_dll2_remove(&rou->list);
|
||||
lws_free(rou);
|
||||
|
||||
|
|
|
@ -559,14 +559,16 @@ lws_create_vhost(struct lws_context *context,
|
|||
#endif
|
||||
int n;
|
||||
|
||||
|
||||
vh = lws_zalloc(sizeof(*vh)
|
||||
if (lws_fi(&info->fic, "vh_create_oom"))
|
||||
vh = NULL;
|
||||
else
|
||||
vh = lws_zalloc(sizeof(*vh)
|
||||
#if defined(LWS_WITH_EVENT_LIBS)
|
||||
+ context->event_loop_ops->evlib_size_vh
|
||||
#endif
|
||||
, __func__);
|
||||
if (!vh)
|
||||
return NULL;
|
||||
goto early_bail;
|
||||
|
||||
#if defined(LWS_WITH_EVENT_LIBS)
|
||||
vh->evlib_vh = (void *)&vh[1];
|
||||
|
@ -599,14 +601,17 @@ lws_create_vhost(struct lws_context *context,
|
|||
info->iface ? info->iface : "", info->port);
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
vh->fi.name = "vh";
|
||||
vh->fi.parent = &context->fi;
|
||||
if (info->fi)
|
||||
vh->fic.name = "vh";
|
||||
if (info->fic.fi_owner.count)
|
||||
/*
|
||||
* This moves all the lws_fi_t from info->fi to the vhost fi,
|
||||
* leaving it empty
|
||||
*/
|
||||
lws_fi_import(&vh->fi, info->fi);
|
||||
lws_fi_import(&vh->fic, &info->fic);
|
||||
|
||||
lws_fi_inherit_copy(&vh->fic, &context->fic, "vh", vh->name);
|
||||
if (lws_fi(&vh->fic, "vh_create_oom"))
|
||||
goto bail;
|
||||
#endif
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
|
@ -725,16 +730,19 @@ lws_create_vhost(struct lws_context *context,
|
|||
* - the ones that came from plugins
|
||||
* - his user protocols
|
||||
*/
|
||||
lwsp = lws_zalloc(sizeof(struct lws_protocols) *
|
||||
|
||||
if (lws_fi(&vh->fic, "vh_create_pcols_oom"))
|
||||
lwsp = NULL;
|
||||
else
|
||||
lwsp = lws_zalloc(sizeof(struct lws_protocols) *
|
||||
((unsigned int)vh->count_protocols +
|
||||
(unsigned int)abs_pcol_count +
|
||||
(unsigned int)sec_pcol_count +
|
||||
(unsigned int)context->plugin_protocol_count +
|
||||
(unsigned int)fx + 1),
|
||||
"vhost-specific plugin table");
|
||||
(unsigned int)fx + 1), "vh plugin table");
|
||||
if (!lwsp) {
|
||||
lwsl_err("OOM\n");
|
||||
return NULL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -923,7 +931,10 @@ lws_create_vhost(struct lws_context *context,
|
|||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
if (info->log_filepath) {
|
||||
vh->log_fd = lws_open(info->log_filepath,
|
||||
if (lws_fi(&vh->fic, "vh_create_access_log_open_fail"))
|
||||
vh->log_fd = (int)LWS_INVALID_FILE;
|
||||
else
|
||||
vh->log_fd = lws_open(info->log_filepath,
|
||||
O_CREAT | O_APPEND | O_RDWR, 0600);
|
||||
if (vh->log_fd == (int)LWS_INVALID_FILE) {
|
||||
lwsl_err("unable to open log filepath %s\n",
|
||||
|
@ -940,17 +951,22 @@ lws_create_vhost(struct lws_context *context,
|
|||
} else
|
||||
vh->log_fd = (int)LWS_INVALID_FILE;
|
||||
#endif
|
||||
if (lws_context_init_server_ssl(info, vh)) {
|
||||
if (lws_fi(&vh->fic, "vh_create_ssl_srv") ||
|
||||
lws_context_init_server_ssl(info, vh)) {
|
||||
lwsl_err("%s: lws_context_init_server_ssl failed\n", __func__);
|
||||
goto bail1;
|
||||
}
|
||||
if (lws_context_init_client_ssl(info, vh)) {
|
||||
if (lws_fi(&vh->fic, "vh_create_ssl_cli") ||
|
||||
lws_context_init_client_ssl(info, vh)) {
|
||||
lwsl_err("%s: lws_context_init_client_ssl failed\n", __func__);
|
||||
goto bail1;
|
||||
}
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
lws_context_lock(context, __func__);
|
||||
n = _lws_vhost_init_server(info, vh);
|
||||
if (lws_fi(&vh->fic, "vh_create_srv_init"))
|
||||
n = -1;
|
||||
else
|
||||
n = _lws_vhost_init_server(info, vh);
|
||||
lws_context_unlock(context);
|
||||
if (n < 0) {
|
||||
lwsl_err("init server failed\n");
|
||||
|
@ -978,7 +994,8 @@ lws_create_vhost(struct lws_context *context,
|
|||
/* for the case we are adding a vhost much later, after server init */
|
||||
|
||||
if (context->protocol_init_done)
|
||||
if (lws_protocol_init(context)) {
|
||||
if (lws_fi(&vh->fic, "vh_create_protocol_init") ||
|
||||
lws_protocol_init(context)) {
|
||||
lwsl_err("%s: lws_protocol_init failed\n", __func__);
|
||||
goto bail1;
|
||||
}
|
||||
|
@ -990,10 +1007,13 @@ bail1:
|
|||
|
||||
return NULL;
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
bail:
|
||||
__lws_lc_untag(&vh->lc);
|
||||
lws_fi_destroy(&vh->fic);
|
||||
lws_free(vh);
|
||||
#endif
|
||||
|
||||
early_bail:
|
||||
lws_fi_destroy(&info->fic);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1449,7 +1469,7 @@ __lws_vhost_destroy2(struct lws_vhost *vh)
|
|||
lws_dll2_remove(&vh->vh_being_destroyed_list);
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_destroy(&vh->fi);
|
||||
lws_fi_destroy(&vh->fic);
|
||||
#endif
|
||||
|
||||
__lws_lc_untag(&vh->lc);
|
||||
|
|
|
@ -240,6 +240,18 @@ __lws_wsi_create_with_role(struct lws_context *context, int tsi,
|
|||
// lwsl_debug("%s: tsi %d: role: %s\n", __func__, tsi,
|
||||
// ops ? ops->name : "none");
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_xos_init(&wsi->fic.xos, lws_xos(&context->fic.xos));
|
||||
#endif
|
||||
|
||||
lws_fi_inherit_copy(&wsi->fic, &context->fic, "wsi", NULL);
|
||||
|
||||
if (lws_fi(&wsi->fic, "createfail")) {
|
||||
lws_fi_destroy(&wsi->fic);
|
||||
lws_free(wsi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
|
|
|
@ -323,6 +323,9 @@ static const char * const opts_str =
|
|||
#if defined(LWS_WITH_MBEDTLS)
|
||||
"MbedTLS "
|
||||
#endif
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
"FLTINJ "
|
||||
#endif
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
"ASYNC_DNS "
|
||||
#endif
|
||||
|
@ -399,6 +402,9 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
char fatal_exit_defer = 0;
|
||||
#endif
|
||||
|
||||
if (lws_fi(&info->fic, "ctx_createfail1"))
|
||||
goto early_bail;
|
||||
|
||||
if (lpf) {
|
||||
lpf+= 2;
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
|
@ -424,7 +430,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
lwsl_notice("%s%s\n", opts_str, s);
|
||||
|
||||
if (lws_plat_context_early_init())
|
||||
return NULL;
|
||||
goto early_bail;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
if (info->count_threads)
|
||||
|
@ -482,7 +488,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
map[n].name, NULL, NULL))
|
||||
ok = 1;
|
||||
|
||||
if (!ok) {
|
||||
if (!ok || lws_fi(&info->fic, "ctx_createfail_plugin_init")) {
|
||||
lwsl_err("%s: failed to load %s\n", __func__,
|
||||
map[n].name);
|
||||
goto bail;
|
||||
|
@ -493,7 +499,8 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
fatal_exit_defer = !!info->foreign_loops;
|
||||
#endif
|
||||
|
||||
if (!evlib_plugin_list) {
|
||||
if (!evlib_plugin_list ||
|
||||
lws_fi(&info->fic, "ctx_createfail_evlib_plugin")) {
|
||||
lwsl_err("%s: unable to load evlib plugin %s\n",
|
||||
__func__, map[n].name);
|
||||
|
||||
|
@ -570,7 +577,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
|
||||
#endif /* not with ev plugins */
|
||||
|
||||
if (!plev)
|
||||
if (!plev || lws_fi(&info->fic, "ctx_createfail_evlib_sel"))
|
||||
goto fail_event_libs;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
|
@ -581,9 +588,12 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
#endif
|
||||
|
||||
context = lws_zalloc(size, "context");
|
||||
if (!context) {
|
||||
lwsl_err("No memory for websocket context\n");
|
||||
return NULL;
|
||||
if (!context || lws_fi(&info->fic, "ctx_createfail_oom_ctx")) {
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_free(context);
|
||||
#endif
|
||||
lwsl_err("No memory for lws_context\n");
|
||||
goto early_bail;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
|
@ -609,13 +619,13 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
context->pt_serv_buf_size = (unsigned int)s1;
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
context->fi.name = "ctx";
|
||||
if (info->fi)
|
||||
context->fic.name = "ctx";
|
||||
if (info->fic.fi_owner.count)
|
||||
/*
|
||||
* This moves all the lws_fi_t from info->fi to the context fi,
|
||||
* leaving it empty, so no injection added to default vhost
|
||||
*/
|
||||
lws_fi_import(&context->fi, info->fi);
|
||||
lws_fi_import(&context->fic, &info->fic);
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -635,16 +645,6 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_UDP)
|
||||
context->udp_loss_sim_tx_pc = info->udp_loss_sim_tx_pc;
|
||||
context->udp_loss_sim_rx_pc = info->udp_loss_sim_rx_pc;
|
||||
|
||||
if (context->udp_loss_sim_tx_pc || context->udp_loss_sim_rx_pc)
|
||||
lwsl_warn("%s: simulating udp loss tx: %d%%, rx: %d%%\n",
|
||||
__func__, context->udp_loss_sim_tx_pc,
|
||||
context->udp_loss_sim_rx_pc);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
context->lcg[LWSLCG_WSI].tag_prefix = "wsi";
|
||||
context->lcg[LWSLCG_VHOST].tag_prefix = "vh";
|
||||
|
@ -800,8 +800,9 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
#endif
|
||||
|
||||
/* if he gave us names, set the uid / gid */
|
||||
if (lws_plat_drop_app_privileges(context, 0))
|
||||
goto bail;
|
||||
if (lws_plat_drop_app_privileges(context, 0) ||
|
||||
lws_fi(&context->fic, "ctx_createfail_privdrop"))
|
||||
goto free_context_fail2;
|
||||
|
||||
#if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
|
@ -900,7 +901,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
if (n == -1) {
|
||||
lwsl_err("Get RLIMIT_NOFILE failed!\n");
|
||||
|
||||
goto free_context_fail;
|
||||
goto free_context_fail2;
|
||||
}
|
||||
context->max_fds = (unsigned int)rt.rlim_cur;
|
||||
#else
|
||||
|
@ -920,11 +921,12 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
context->max_fds = (unsigned int)l;
|
||||
}
|
||||
#endif
|
||||
if ((int)context->max_fds < 0) {
|
||||
if ((int)context->max_fds < 0 ||
|
||||
lws_fi(&context->fic, "ctx_createfail_maxfds")) {
|
||||
lwsl_err("%s: problem getting process max files\n",
|
||||
__func__);
|
||||
|
||||
goto free_context_fail;
|
||||
goto free_context_fail2;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1094,7 +1096,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
|
||||
if (!info->ka_interval && info->ka_time > 0) {
|
||||
lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
|
||||
return NULL;
|
||||
goto free_context_fail;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
|
@ -1120,9 +1122,13 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
n = (int)(sizeof(struct lws_pollfd) * context->count_threads *
|
||||
context->fd_limit_per_thread);
|
||||
context->pt[0].fds = lws_zalloc((unsigned int)n, "fds table");
|
||||
if (context->pt[0].fds == NULL) {
|
||||
if (context->pt[0].fds == NULL ||
|
||||
lws_fi(&context->fic, "ctx_createfail_oom_fds")) {
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_free(context->pt[0].fds);
|
||||
#endif
|
||||
lwsl_err("OOM allocating %d fds\n", context->max_fds);
|
||||
goto bail;
|
||||
goto free_context_fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1163,14 +1169,21 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
* loop and if libuv, have to take care about how to unpick them...
|
||||
*/
|
||||
|
||||
if (lws_plat_init(context, info))
|
||||
if (lws_plat_init(context, info) ||
|
||||
lws_fi(&context->fic, "ctx_createfail_plat_init"))
|
||||
goto bail_libuv_aware;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
|
||||
if (lws_fi(&context->fic, "ctx_createfail_evlib_init"))
|
||||
goto bail_libuv_aware;
|
||||
|
||||
if (context->event_loop_ops->init_context)
|
||||
if (context->event_loop_ops->init_context(context, info))
|
||||
goto bail_libuv_aware;
|
||||
|
||||
if (lws_fi(&context->fic, "ctx_createfail_evlib_pt"))
|
||||
goto bail_libuv_aware;
|
||||
|
||||
if (context->event_loop_ops->init_pt)
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
|
@ -1255,7 +1268,10 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
ii.pprotocols = pp;
|
||||
ii.port = CONTEXT_PORT_NO_LISTEN;
|
||||
|
||||
vh = lws_create_vhost(context, &ii);
|
||||
if (lws_fi(&context->fic, "ctx_createfail_sys_vh"))
|
||||
vh = NULL;
|
||||
else
|
||||
vh = lws_create_vhost(context, &ii);
|
||||
if (!vh) {
|
||||
lwsl_err("%s: failed to create system vhost\n",
|
||||
__func__);
|
||||
|
@ -1264,7 +1280,8 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
|
||||
context->vhost_system = vh;
|
||||
|
||||
if (lws_protocol_init_vhost(vh, NULL)) {
|
||||
if (lws_protocol_init_vhost(vh, NULL) ||
|
||||
lws_fi(&context->fic, "ctx_createfail_sys_vh_init")) {
|
||||
lwsl_err("%s: failed to init system vhost\n", __func__);
|
||||
goto bail_libuv_aware;
|
||||
}
|
||||
|
@ -1309,15 +1326,17 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
* if he's not saying he'll make his own vhosts later then act
|
||||
* compatibly and make a default vhost using the data in the info
|
||||
*/
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
|
||||
if (!lws_create_vhost(context, info)) {
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
|
||||
if (!lws_create_vhost(context, info) ||
|
||||
lws_fi(&context->fic, "ctx_createfail_def_vh")) {
|
||||
lwsl_err("Failed to create default vhost\n");
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
lws_free_set_NULL(context->pl_hash_table);
|
||||
#endif
|
||||
goto fail_clean_pipes;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
|
||||
|
@ -1330,16 +1349,25 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
assert(lws_check_opt(info->options,
|
||||
LWS_SERVER_OPTION_EXPLICIT_VHOSTS));
|
||||
|
||||
if (lws_ss_policy_parse_begin(context, 0))
|
||||
if (lws_ss_policy_parse_begin(context, 0) ||
|
||||
lws_fi(&context->fic, "ctx_createfail_ss_pol1")) {
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_ss_policy_parse_abandon(context);
|
||||
#endif
|
||||
goto bail_libuv_aware;
|
||||
}
|
||||
|
||||
n = lws_ss_policy_parse(context,
|
||||
(uint8_t *)context->pss_policies_json,
|
||||
strlen(context->pss_policies_json));
|
||||
if (n != LEJP_CONTINUE && n < 0)
|
||||
if ((n != LEJP_CONTINUE && n < 0) ||
|
||||
lws_fi(&context->fic, "ctx_createfail_ss_pol2")) {
|
||||
lws_ss_policy_parse_abandon(context);
|
||||
goto bail_libuv_aware;
|
||||
}
|
||||
|
||||
if (lws_ss_policy_set(context, "hardcoded")) {
|
||||
if (lws_ss_policy_set(context, "hardcoded") ||
|
||||
lws_fi(&context->fic, "ctx_createfail_ss_pol3")) {
|
||||
lwsl_err("%s: policy set failed\n", __func__);
|
||||
goto bail_libuv_aware;
|
||||
}
|
||||
|
@ -1348,7 +1376,8 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
if (context->pss_policies) {
|
||||
/* user code set the policy objects directly, no parsing step */
|
||||
|
||||
if (lws_ss_policy_set(context, "hardcoded")) {
|
||||
if (lws_ss_policy_set(context, "hardcoded") ||
|
||||
lws_fi(&context->fic, "ctx_createfail_ss_pol3")) {
|
||||
lwsl_err("%s: policy set failed\n", __func__);
|
||||
goto bail_libuv_aware;
|
||||
}
|
||||
|
@ -1368,7 +1397,8 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
* listening, we don't want the power for anything else
|
||||
*/
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
|
||||
if (lws_plat_drop_app_privileges(context, 1))
|
||||
if (lws_plat_drop_app_privileges(context, 1) ||
|
||||
lws_fi(&context->fic, "ctx_createfail_privdrop"))
|
||||
goto bail_libuv_aware;
|
||||
|
||||
#if defined(LWS_WITH_SYS_STATE)
|
||||
|
@ -1391,6 +1421,12 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
|
||||
return context;
|
||||
|
||||
early_bail:
|
||||
lws_fi_destroy(&info->fic);
|
||||
|
||||
return NULL;
|
||||
|
||||
#if 0
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
fail_clean_pipes:
|
||||
|
||||
|
@ -1410,11 +1446,15 @@ fail_clean_pipes:
|
|||
|
||||
return NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
bail:
|
||||
lws_fi_destroy(&info->fic);
|
||||
lws_context_destroy(context);
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
bail_libuv_aware:
|
||||
lws_context_destroy(context);
|
||||
|
@ -1429,7 +1469,22 @@ fail_event_libs:
|
|||
lwsl_err("Requested event library support not configured\n");
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
free_context_fail:
|
||||
if (context) {
|
||||
#if defined(LWS_WITH_SYS_SMD)
|
||||
_lws_smd_destroy(context);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
free_context_fail2:
|
||||
if (context) {
|
||||
#if defined(LWS_WITH_SYS_METRICS)
|
||||
lws_metrics_destroy(context);
|
||||
#endif
|
||||
lws_fi_destroy(&context->fic);
|
||||
}
|
||||
lws_fi_destroy(&info->fic);
|
||||
lws_free(context);
|
||||
|
||||
return NULL;
|
||||
|
@ -1912,6 +1967,7 @@ next:
|
|||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
struct lws_context_per_thread *pt = &context->pt[n];
|
||||
|
||||
(void)pt;
|
||||
#if defined(LWS_WITH_SEQUENCER)
|
||||
lws_seq_destroy_all_on_pt(pt);
|
||||
|
@ -2074,7 +2130,7 @@ next:
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_destroy(&context->fi);
|
||||
lws_fi_destroy(&context->fic);
|
||||
#endif
|
||||
|
||||
lws_free(context);
|
||||
|
|
|
@ -1335,13 +1335,18 @@ lws_cmdline_option(int argc, const char **argv, const char *val)
|
|||
|
||||
static const char * const builtins[] = {
|
||||
"-d",
|
||||
#if defined(LWS_WITH_UDP)
|
||||
"--udp-tx-loss",
|
||||
"--udp-rx-loss",
|
||||
#endif
|
||||
"--fault-injection",
|
||||
"--fault-seed",
|
||||
"--ignore-sigterm"
|
||||
};
|
||||
|
||||
enum opts {
|
||||
OPT_DEBUGLEVEL,
|
||||
OPT_FAULTINJECTION,
|
||||
OPT_FAULT_SEED,
|
||||
OPT_IGNORE_SIGTERM,
|
||||
};
|
||||
|
||||
#if !defined(LWS_PLAT_FREERTOS)
|
||||
static void
|
||||
lws_sigterm_catch(int sig)
|
||||
|
@ -1355,6 +1360,9 @@ lws_cmdline_option_handle_builtin(int argc, const char **argv,
|
|||
{
|
||||
const char *p;
|
||||
int n, m, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
uint64_t seed = (uint64_t)lws_now_usecs();
|
||||
#endif
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(builtins); n++) {
|
||||
p = lws_cmdline_option(argc, argv, builtins[n]);
|
||||
|
@ -1364,20 +1372,24 @@ lws_cmdline_option_handle_builtin(int argc, const char **argv,
|
|||
m = atoi(p);
|
||||
|
||||
switch (n) {
|
||||
case 0:
|
||||
case OPT_DEBUGLEVEL:
|
||||
logs = m;
|
||||
break;
|
||||
#if defined(LWS_WITH_UDP)
|
||||
case 1:
|
||||
info->udp_loss_sim_tx_pc = (uint8_t)m;
|
||||
break;
|
||||
case 2:
|
||||
info->udp_loss_sim_rx_pc = (uint8_t)m;
|
||||
break;
|
||||
case 3:
|
||||
#else
|
||||
case 1:
|
||||
|
||||
case OPT_FAULTINJECTION:
|
||||
#if !defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lwsl_err("%s: FAULT_INJECTION not built\n", __func__);
|
||||
#endif
|
||||
lws_fi_deserialize(&info->fic, p);
|
||||
break;
|
||||
|
||||
case OPT_FAULT_SEED:
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
seed = (uint64_t)atoll(p);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case OPT_IGNORE_SIGTERM:
|
||||
#if !defined(LWS_PLAT_FREERTOS)
|
||||
signal(SIGTERM, lws_sigterm_catch);
|
||||
#endif
|
||||
|
@ -1385,7 +1397,16 @@ lws_cmdline_option_handle_builtin(int argc, const char **argv,
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_xos_init(&info->fic.xos, seed);
|
||||
#endif
|
||||
lws_set_log_level(logs, NULL);
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
if (info->fic.fi_owner.count)
|
||||
lwsl_notice("%s: Fault Injection seed %llu\n", __func__,
|
||||
(unsigned long long)seed);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -524,7 +524,7 @@ struct lws_context {
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t fi;
|
||||
lws_fi_ctx_t fic;
|
||||
/**< Toplevel Fault Injection ctx */
|
||||
#endif
|
||||
|
||||
|
@ -729,8 +729,6 @@ struct lws_context {
|
|||
uint16_t us_wait_resolution;
|
||||
|
||||
uint8_t max_fi;
|
||||
uint8_t udp_loss_sim_tx_pc;
|
||||
uint8_t udp_loss_sim_rx_pc;
|
||||
uint8_t captive_portal_detect;
|
||||
uint8_t captive_portal_detect_type;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ include_directories(.)
|
|||
|
||||
list(APPEND SOURCES
|
||||
misc/base64-decode.c
|
||||
misc/prng.c
|
||||
misc/lws-ring.c)
|
||||
|
||||
if (LWS_WITH_FTS)
|
||||
|
|
80
lib/misc/prng.c
Normal file
80
lib/misc/prng.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* After Public Domain implementations
|
||||
*
|
||||
* https://github.com/svaarala/duktape/tree/master/misc
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
|
||||
static inline uint64_t rol64(uint64_t x, int k)
|
||||
{
|
||||
return (x << k) | (x >> (64 - k));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
lws_xos(struct lws_xos *xos)
|
||||
{
|
||||
uint64_t *s = &xos->s[0];
|
||||
uint64_t const result = rol64(s[1] * 5, 7) * 9;
|
||||
uint64_t const c = s[1] << 17;
|
||||
|
||||
s[2] ^= s[0];
|
||||
s[3] ^= s[1];
|
||||
s[1] ^= s[2];
|
||||
s[0] ^= s[3];
|
||||
|
||||
s[2] ^= c;
|
||||
s[3] = rol64(s[3], 45);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
splitmix64(uint64_t *s)
|
||||
{
|
||||
uint64_t r = *s;
|
||||
|
||||
*s = r + 0x9E3779B97F4A7C15ull;
|
||||
|
||||
r = (r ^ (r >> 30)) * 0xBF58476D1CE4E5B9ull;
|
||||
r = (r ^ (r >> 27)) * 0x94D049BB133111EBull;
|
||||
|
||||
return r ^ (r >> 31);
|
||||
}
|
||||
|
||||
void
|
||||
lws_xos_init(struct lws_xos *xos, uint64_t seed)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 4; n++)
|
||||
xos->s[n] = splitmix64(&seed);
|
||||
}
|
||||
|
||||
int
|
||||
lws_xos_percent(struct lws_xos *xos, int percent)
|
||||
{
|
||||
return (int)(lws_xos(xos) % 100) < percent;
|
||||
}
|
|
@ -54,6 +54,7 @@ _lws_plat_service_forced_tsi(struct lws_context *context, int tsi)
|
|||
__func__, m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if something closed, retry this slot since may have been
|
||||
* swapped with end fd */
|
||||
if (m && pt->fds[n].fd != fd)
|
||||
|
|
|
@ -1459,6 +1459,9 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
|
|||
|
||||
/* pass on the initial headers to SID 1 */
|
||||
h2n->swsi->http.ah = wsi->http.ah;
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_import(&h2n->swsi->fic, &wsi->fic);
|
||||
#endif
|
||||
h2n->swsi->client_mux_substream = 1;
|
||||
h2n->swsi->client_h2_alpn = 1;
|
||||
#if defined(LWS_WITH_CLIENT)
|
||||
|
|
|
@ -175,17 +175,23 @@ done_list:
|
|||
#endif
|
||||
|
||||
for (m = 0; m < limit; m++) {
|
||||
|
||||
if (lws_fi(&vhost->fic, "listenskt")) {
|
||||
sockfd = LWS_SOCK_INVALID;
|
||||
} else {
|
||||
|
||||
#ifdef LWS_WITH_UNIX_SOCK
|
||||
if (LWS_UNIX_SOCK_ENABLED(vhost))
|
||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
else
|
||||
if (LWS_UNIX_SOCK_ENABLED(vhost))
|
||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
else
|
||||
#endif
|
||||
#ifdef LWS_WITH_IPV6
|
||||
if (LWS_IPV6_ENABLED(vhost))
|
||||
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
else
|
||||
if (LWS_IPV6_ENABLED(vhost))
|
||||
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
else
|
||||
#endif
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
if (sockfd == LWS_SOCK_INVALID) {
|
||||
lwsl_err("ERROR opening socket\n");
|
||||
|
|
|
@ -142,20 +142,9 @@ rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
|
|||
}
|
||||
|
||||
#if defined(LWS_WITH_UDP)
|
||||
if (wsi->a.context->udp_loss_sim_rx_pc) {
|
||||
uint16_t u16;
|
||||
/*
|
||||
* We should randomly drop some of these
|
||||
*/
|
||||
|
||||
if (lws_get_random(wsi->a.context, &u16, 2) == 2 &&
|
||||
((u16 * 100) / 0xffff) <=
|
||||
wsi->a.context->udp_loss_sim_rx_pc) {
|
||||
lwsl_warn("%s: dropping udp rx\n", __func__);
|
||||
/* pretend it was handled */
|
||||
n = ebuf.len;
|
||||
goto post_rx;
|
||||
}
|
||||
if (lws_fi(&wsi->fic, "udp_rx_loss")) {
|
||||
n = ebuf.len;
|
||||
goto post_rx;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1115,6 +1115,21 @@ int
|
|||
lws_ss_policy_parse_abandon(struct lws_context *context)
|
||||
{
|
||||
struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
|
||||
lws_ss_x509_t *x;
|
||||
|
||||
x = args->heads[LTY_X509].x;
|
||||
while (x) {
|
||||
/*
|
||||
* Free all the client DER buffers now they have been parsed
|
||||
* into tls library X.509 objects
|
||||
*/
|
||||
if (!x->keep) { /* used for server */
|
||||
lws_free((void *)x->ca_der);
|
||||
x->ca_der = NULL;
|
||||
}
|
||||
|
||||
x = x->next;
|
||||
}
|
||||
|
||||
lejp_destruct(&args->jctx);
|
||||
lwsac_free(&args->ac);
|
||||
|
|
|
@ -59,7 +59,7 @@ typedef struct lws_ss_handle {
|
|||
struct lws_dll2 cli_list; /**< same server clients list */
|
||||
#endif
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t fi; /**< Fault Injection context */
|
||||
lws_fi_ctx_t fic; /**< Fault Injection context */
|
||||
#endif
|
||||
|
||||
struct lws_dll2_owner src_list; /**< sink's list of bound sources */
|
||||
|
@ -285,7 +285,7 @@ typedef struct lws_sspc_handle {
|
|||
struct lws_ss_serialization_parser parser;
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t fi; /**< Fault Injection context */
|
||||
lws_fi_ctx_t fic; /**< Fault Injection context */
|
||||
#endif
|
||||
|
||||
lws_dll2_owner_t metadata_owner;
|
||||
|
@ -402,7 +402,7 @@ lws_ss_deserialize_tx_payload(struct lws_dsh *dsh, struct lws *wsi,
|
|||
lws_ss_tx_ordinal_t ord, uint8_t *buf,
|
||||
size_t *len, int *flags);
|
||||
int
|
||||
lws_ss_serialize_state(struct lws_dsh *dsh, lws_ss_constate_t state,
|
||||
lws_ss_serialize_state(struct lws *wsi, struct lws_dsh *dsh, lws_ss_constate_t state,
|
||||
lws_ss_tx_ordinal_t ack);
|
||||
|
||||
void
|
||||
|
|
|
@ -174,7 +174,7 @@ callback_sspc_client(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_CONNECTED:
|
||||
if (!h)
|
||||
if (!h || lws_fi(&h->fic, "sspc_fail_on_linkup"))
|
||||
return -1;
|
||||
lwsl_info("%s: CONNECTED (%s)\n", __func__, h->ssi.streamtype);
|
||||
|
||||
|
@ -234,9 +234,18 @@ callback_sspc_client(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
return -1;
|
||||
}
|
||||
|
||||
n = lws_ss_deserialize_parse(&h->parser, lws_get_context(wsi),
|
||||
h->dsh, in, len, &h->state, h,
|
||||
(lws_ss_handle_t **)m, &h->ssi, 1);
|
||||
if (lws_fi(&h->fic, "sspc_fake_rxparse_disconnect_me"))
|
||||
n = LWSSSSRET_DISCONNECT_ME;
|
||||
else
|
||||
if (lws_fi(&h->fic, "sspc_fake_rxparse_destroy_me"))
|
||||
n = LWSSSSRET_DESTROY_ME;
|
||||
else
|
||||
n = lws_ss_deserialize_parse(&h->parser,
|
||||
lws_get_context(wsi),
|
||||
h->dsh, in, len,
|
||||
&h->state, h,
|
||||
(lws_ss_handle_t **)m,
|
||||
&h->ssi, 1);
|
||||
switch (n) {
|
||||
case LWSSSSRET_OK:
|
||||
break;
|
||||
|
@ -476,7 +485,10 @@ do_write_nz:
|
|||
break;
|
||||
|
||||
do_write:
|
||||
n = lws_write(wsi, (uint8_t *)cp, (unsigned int)n, LWS_WRITE_RAW);
|
||||
if (lws_fi(&h->fic, "sspc_link_write_fail"))
|
||||
n = -1;
|
||||
else
|
||||
n = lws_write(wsi, (uint8_t *)cp, (unsigned int)n, LWS_WRITE_RAW);
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: WRITEABLE: %d\n", __func__, n);
|
||||
|
||||
|
@ -530,20 +542,32 @@ lws_sspc_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
|||
* and the streamname */
|
||||
|
||||
h = malloc(sizeof(lws_sspc_handle_t) + ssi->user_alloc +
|
||||
strlen(ssi->streamtype) + 1);
|
||||
strlen(ssi->streamtype) + 1);
|
||||
if (!h)
|
||||
return 1;
|
||||
memset(h, 0, sizeof(*h));
|
||||
|
||||
__lws_lc_tag(&context->lcg[LWSLCG_SSP_CLIENT], &h->lc, ssi->streamtype);
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
h->fi.name = "sspc";
|
||||
h->fi.parent = &context->fi;
|
||||
if (ssi->fi)
|
||||
lws_fi_import(&h->fi, ssi->fi);
|
||||
h->fic.name = "sspc";
|
||||
lws_xos_init(&h->fic.xos, lws_xos(&context->fic.xos));
|
||||
if (ssi->fic.fi_owner.count)
|
||||
lws_fi_import(&h->fic, &ssi->fic);
|
||||
|
||||
lws_fi_inherit_copy(&h->fic, &context->fic, "ss", ssi->streamtype);
|
||||
#endif
|
||||
|
||||
if (lws_fi(&h->fic, "sspc_create_oom")) {
|
||||
/*
|
||||
* We have to do this a litte later, so we can cleanly inherit
|
||||
* the OOM pieces and drain the info fic
|
||||
*/
|
||||
lws_fi_destroy(&h->fic);
|
||||
free(h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
__lws_lc_tag(&context->lcg[LWSLCG_SSP_CLIENT], &h->lc, ssi->streamtype);
|
||||
|
||||
memcpy(&h->ssi, ssi, sizeof(*ssi));
|
||||
ua = (uint8_t *)&h[1];
|
||||
memset(ua, 0, ssi->user_alloc);
|
||||
|
@ -633,7 +657,7 @@ lws_sspc_destroy(lws_sspc_handle_t **ph)
|
|||
}
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_destroy(&h->fi);
|
||||
lws_fi_destroy(&h->fic);
|
||||
#endif
|
||||
|
||||
lws_sul_cancel(&h->sul_retry);
|
||||
|
@ -823,7 +847,10 @@ _lws_sspc_set_metadata(struct lws_sspc_handle *h, const char *name,
|
|||
* We have to stash the metadata and pass it to the proxy
|
||||
*/
|
||||
|
||||
md = lws_malloc(sizeof(*md) + len, "set metadata");
|
||||
if (lws_fi(&h->fic, "sspc_fail_metadata_set"))
|
||||
md = NULL;
|
||||
else
|
||||
md = lws_malloc(sizeof(*md) + len, "set metadata");
|
||||
if (!md) {
|
||||
lwsl_err("%s: OOM\n", __func__);
|
||||
|
||||
|
|
|
@ -91,6 +91,8 @@ __lws_ss_proxy_bind_ss_to_conn_wsi(void *parconn, size_t dsh_size)
|
|||
|
||||
pt = &conn->wsi->a.context->pt[(int)conn->wsi->tsi];
|
||||
|
||||
if (lws_fi(&conn->ss->fic, "ssproxy_dsh_create_oom"))
|
||||
return -1;
|
||||
conn->dsh = lws_dsh_create(&pt->ss_dsh_owner, dsh_size, 2);
|
||||
if (!conn->dsh)
|
||||
return -1;
|
||||
|
@ -100,7 +102,7 @@ __lws_ss_proxy_bind_ss_to_conn_wsi(void *parconn, size_t dsh_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* secure streams payload interface */
|
||||
/* Onward secure streams payload interface */
|
||||
|
||||
static lws_ss_state_return_t
|
||||
ss_proxy_onward_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
|
||||
|
@ -120,9 +122,22 @@ ss_proxy_onward_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
|
|||
flags |= LWSSS_FLAG_RIDESHARE;
|
||||
}
|
||||
|
||||
n = lws_ss_serialize_rx_payload(m->conn->dsh, buf, len, flags, rsp);
|
||||
/*
|
||||
* Apply SSS framing around this chunk of RX and stash it in the dsh
|
||||
* in ss -> proxy [ -> client] direction. This can fail...
|
||||
*/
|
||||
|
||||
if (lws_fi(&m->ss->fic, "ssproxy_dsh_rx_queue_oom"))
|
||||
n = 1;
|
||||
else
|
||||
n = lws_ss_serialize_rx_payload(m->conn->dsh, buf, len,
|
||||
flags, rsp);
|
||||
if (n)
|
||||
return n;
|
||||
/*
|
||||
* We couldn't buffer this rx, eg due to OOM, let's escalate it
|
||||
* to be a "loss of connection", which it basically is...
|
||||
*/
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
|
||||
/*
|
||||
* Manage rx flow on the SS (onward) side according to our situation
|
||||
|
@ -141,7 +156,7 @@ ss_proxy_onward_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
|
|||
if (m->conn->wsi) /* if possible, request client conn write */
|
||||
lws_callback_on_writable(m->conn->wsi);
|
||||
|
||||
return 0;
|
||||
return LWSSSSRET_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -221,6 +236,8 @@ ss_proxy_onward_state(void *userobj, void *sh,
|
|||
__func__, lws_ss_tag(m->ss),
|
||||
(unsigned long)dsh_size);
|
||||
|
||||
/* this includes ssproxy_dsh_create_oom fault generation */
|
||||
|
||||
if (__lws_ss_proxy_bind_ss_to_conn_wsi(m->conn, dsh_size)) {
|
||||
|
||||
/* failed to allocate the dsh */
|
||||
|
@ -257,7 +274,12 @@ ss_proxy_onward_state(void *userobj, void *sh,
|
|||
return LWSSSSRET_OK;
|
||||
}
|
||||
|
||||
lws_ss_serialize_state(m->conn->dsh, state, ack);
|
||||
if (lws_ss_serialize_state(m->conn->wsi, m->conn->dsh, state, ack))
|
||||
/*
|
||||
* Failed to alloc state packet that we want to send in dsh,
|
||||
* we will lose coherence and have to disconnect the link
|
||||
*/
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
|
||||
if (m->conn->wsi) /* if possible, request client conn write */
|
||||
lws_callback_on_writable(m->conn->wsi);
|
||||
|
@ -280,7 +302,7 @@ ss_proxy_onward_txcr(void *userobj, int bump)
|
|||
}
|
||||
|
||||
/*
|
||||
* Client - Proxy connection on unix domain socket
|
||||
* Client <-> Proxy connection, usually on Unix Domain Socket
|
||||
*/
|
||||
|
||||
static int
|
||||
|
@ -315,9 +337,14 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
lwsl_info("LWS_CALLBACK_RAW_ADOPT\n");
|
||||
if (!pss)
|
||||
return -1;
|
||||
pss->conn = malloc(sizeof(struct conn));
|
||||
|
||||
if (lws_fi(&wsi->fic, "ssproxy_client_adopt_oom"))
|
||||
pss->conn = NULL;
|
||||
else
|
||||
pss->conn = malloc(sizeof(struct conn));
|
||||
if (!pss->conn)
|
||||
return -1;
|
||||
|
||||
memset(pss->conn, 0, sizeof(*pss->conn));
|
||||
|
||||
/* dsh is allocated when the onward ss is done */
|
||||
|
@ -354,8 +381,8 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
assert(conn->wsi == wsi);
|
||||
conn->wsi = NULL;
|
||||
|
||||
lwsl_notice("%s: cli->prox link %s closing\n",
|
||||
__func__, lws_wsi_tag(wsi));
|
||||
lwsl_notice("%s: cli->prox link %s closing\n", __func__,
|
||||
lws_wsi_tag(wsi));
|
||||
|
||||
/* sever relationship with conn */
|
||||
lws_set_opaque_user_data(wsi, NULL);
|
||||
|
@ -518,9 +545,11 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
conn->state = LPCSPROX_OPERATIONAL;
|
||||
lws_set_timeout(wsi, 0, 0);
|
||||
break;
|
||||
|
||||
case LPCSPROX_OPERATIONAL:
|
||||
|
||||
/*
|
||||
* returning [onward -> ] proxy]-> client
|
||||
* rx metadata has priority
|
||||
*/
|
||||
|
||||
|
@ -546,7 +575,8 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
p[3] = (uint8_t)naml;
|
||||
memcpy(&p[4], md->name, naml);
|
||||
p += 4 + naml;
|
||||
memcpy(p, md->value__may_own_heap, md->length);
|
||||
memcpy(p, md->value__may_own_heap,
|
||||
md->length);
|
||||
p += md->length;
|
||||
|
||||
n = lws_ptr_diff(p, cp);
|
||||
|
@ -607,7 +637,10 @@ again:
|
|||
if (!n)
|
||||
break;
|
||||
|
||||
n = lws_write(wsi, (uint8_t *)cp, (unsigned int)n, LWS_WRITE_RAW);
|
||||
if (lws_fi(&wsi->fic, "ssproxy_client_write_fail"))
|
||||
n = -1;
|
||||
else
|
||||
n = lws_write(wsi, (uint8_t *)cp, (unsigned int)n, LWS_WRITE_RAW);
|
||||
if (n < 0) {
|
||||
lwsl_info("%s: WRITEABLE: %d\n", __func__, n);
|
||||
|
||||
|
|
|
@ -262,7 +262,7 @@ lws_ss_deserialize_tx_payload(struct lws_dsh *dsh, struct lws *wsi,
|
|||
*/
|
||||
|
||||
int
|
||||
lws_ss_serialize_state(struct lws_dsh *dsh, lws_ss_constate_t state,
|
||||
lws_ss_serialize_state(struct lws *wsi, struct lws_dsh *dsh, lws_ss_constate_t state,
|
||||
lws_ss_tx_ordinal_t ack)
|
||||
{
|
||||
uint8_t pre[12];
|
||||
|
@ -285,7 +285,8 @@ lws_ss_serialize_state(struct lws_dsh *dsh, lws_ss_constate_t state,
|
|||
|
||||
lws_ser_wu32be(&pre[n], ack);
|
||||
|
||||
if (lws_dsh_alloc_tail(dsh, KIND_SS_TO_P, pre, (unsigned int)n + 4, NULL, 0)) {
|
||||
if (lws_dsh_alloc_tail(dsh, KIND_SS_TO_P, pre, (unsigned int)n + 4, NULL, 0) ||
|
||||
(wsi && lws_fi(&wsi->fic, "sspc_dsh_ss2p_oom"))) {
|
||||
lwsl_err("%s: unable to alloc in dsh 2\n", __func__);
|
||||
|
||||
return 1;
|
||||
|
@ -428,7 +429,9 @@ lws_ss_deserialize_parse(struct lws_ss_serialization_parser *par,
|
|||
* We're going to try to do the onward connect
|
||||
*/
|
||||
|
||||
if (_lws_ss_client_connect(proxy_pss_to_ss_h(pss),
|
||||
if ((proxy_pss_to_ss_h(pss) &&
|
||||
lws_fi(&proxy_pss_to_ss_h(pss)->fic, "ssproxy_onward_conn_fail")) ||
|
||||
_lws_ss_client_connect(proxy_pss_to_ss_h(pss),
|
||||
0, parconn) ==
|
||||
LWSSSSRET_DESTROY_ME)
|
||||
goto hangup;
|
||||
|
@ -685,7 +688,9 @@ payload_ff:
|
|||
/* time used later to find proxy hold time */
|
||||
lws_ser_wu64be(&p[15], (uint64_t)us);
|
||||
|
||||
if (lws_dsh_alloc_tail(dsh, KIND_C_TO_P, pre,
|
||||
if ((proxy_pss_to_ss_h(pss) &&
|
||||
lws_fi(&proxy_pss_to_ss_h(pss)->fic, "ssproxy_dsh_c2p_pay_oom")) ||
|
||||
lws_dsh_alloc_tail(dsh, KIND_C_TO_P, pre,
|
||||
23, cp, (unsigned int)n)) {
|
||||
lwsl_err("%s: unable to alloc in dsh 3\n",
|
||||
__func__);
|
||||
|
@ -715,6 +720,11 @@ payload_ff:
|
|||
/* we still have an sspc handle */
|
||||
int ret = ssi->rx(client_pss_to_userdata(pss),
|
||||
(uint8_t *)cp, (unsigned int)n, (int)flags);
|
||||
|
||||
if (client_pss_to_sspc_h(pss, ssi) &&
|
||||
lws_fi(&client_pss_to_sspc_h(pss, ssi)->fic, "sspc_rx_fake_destroy_me"))
|
||||
ret = LWSSSSRET_DESTROY_ME;
|
||||
|
||||
switch (ret) {
|
||||
case LWSSSSRET_OK:
|
||||
break;
|
||||
|
@ -1005,7 +1015,10 @@ payload_ff:
|
|||
* Create the client's rx metadata entry
|
||||
*/
|
||||
|
||||
md = lws_malloc(sizeof(lws_sspc_metadata_t) +
|
||||
if (h && lws_fi(&h->fic, "sspc_rx_metadata_oom"))
|
||||
md = NULL;
|
||||
else
|
||||
md = lws_malloc(sizeof(lws_sspc_metadata_t) +
|
||||
par->rem + 1, "rxmeta");
|
||||
if (!md) {
|
||||
lwsl_err("%s: OOM\n", __func__);
|
||||
|
@ -1057,7 +1070,13 @@ payload_ff:
|
|||
lws_free_set_NULL(par->ssmd->value__may_own_heap);
|
||||
par->ssmd->value_on_lws_heap = 0;
|
||||
|
||||
par->ssmd->value__may_own_heap = lws_malloc((unsigned int)par->rem + 1, "metadata");
|
||||
if (proxy_pss_to_ss_h(pss) &&
|
||||
lws_fi(&proxy_pss_to_ss_h(pss)->fic, "ssproxy_rx_metadata_oom"))
|
||||
par->ssmd->value__may_own_heap = NULL;
|
||||
else
|
||||
par->ssmd->value__may_own_heap =
|
||||
lws_malloc((unsigned int)par->rem + 1, "metadata");
|
||||
|
||||
if (!par->ssmd->value__may_own_heap) {
|
||||
lwsl_err("%s: OOM mdv\n", __func__);
|
||||
goto hangup;
|
||||
|
|
|
@ -747,7 +747,29 @@ lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
|||
pol = ssi->policy;
|
||||
if (!pol) {
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_ctx_t temp_fic;
|
||||
|
||||
/*
|
||||
* We have to do a temp inherit from context to find out
|
||||
* early if we are supposed to inject a fault concealing
|
||||
* the policy
|
||||
*/
|
||||
|
||||
memset(&temp_fic, 0, sizeof(temp_fic));
|
||||
lws_xos_init(&temp_fic.xos, lws_xos(&context->fic.xos));
|
||||
lws_fi_inherit_copy(&temp_fic, &context->fic, "ss", ssi->streamtype);
|
||||
|
||||
if (lws_fi(&temp_fic, "ss_no_streamtype_policy"))
|
||||
pol = NULL;
|
||||
else
|
||||
pol = lws_ss_policy_lookup(context, ssi->streamtype);
|
||||
|
||||
lws_fi_destroy(&temp_fic);
|
||||
#else
|
||||
pol = lws_ss_policy_lookup(context, ssi->streamtype);
|
||||
#endif
|
||||
if (!pol) {
|
||||
lwsl_info("%s: unknown stream type %s\n", __func__,
|
||||
ssi->streamtype);
|
||||
|
@ -821,10 +843,12 @@ lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
|||
ssi->streamtype ? ssi->streamtype : "nostreamtype");
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
h->fi.name = "ss";
|
||||
h->fi.parent = &context->fi;
|
||||
if (ssi->fi)
|
||||
lws_fi_import(&h->fi, ssi->fi);
|
||||
h->fic.name = "ss";
|
||||
lws_xos_init(&h->fic.xos, lws_xos(&context->fic.xos));
|
||||
if (ssi->fic.fi_owner.count)
|
||||
lws_fi_import(&h->fic, &ssi->fic);
|
||||
|
||||
lws_fi_inherit_copy(&h->fic, &context->fic, "ss", ssi->streamtype);
|
||||
#endif
|
||||
|
||||
h->info = *ssi;
|
||||
|
@ -980,7 +1004,10 @@ lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
|||
}
|
||||
#endif
|
||||
|
||||
vho = lws_create_vhost(context, &i);
|
||||
if (lws_fi(&ssi->fic, "ss_srv_vh_fail"))
|
||||
vho = NULL;
|
||||
else
|
||||
vho = lws_create_vhost(context, &i);
|
||||
if (!vho) {
|
||||
lwsl_err("%s: failed to create vh", __func__);
|
||||
goto late_bail;
|
||||
|
@ -1037,6 +1064,7 @@ late_bail:
|
|||
lws_dll2_remove(&h->list);
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
lws_fi_destroy(&h->fic);
|
||||
__lws_lc_untag(&h->lc);
|
||||
lws_free(h);
|
||||
|
||||
|
@ -1199,7 +1227,7 @@ lws_ss_destroy(lws_ss_handle_t **ppss)
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
lws_fi_destroy(&h->fi);
|
||||
lws_fi_destroy(&h->fic);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SYS_METRICS)
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
static const uint32_t botable[] = { 300, 500, 700, 1250, 5000
|
||||
/* in case everything just dog slow */ };
|
||||
static const lws_retry_bo_t retry_policy = {
|
||||
botable, LWS_ARRAY_SIZE(botable), LWS_ARRAY_SIZE(botable),
|
||||
botable, LWS_ARRAY_SIZE(botable), LWS_RETRY_CONCEAL_ALWAYS,
|
||||
/* don't conceal after the last table entry */ 0, 0, 20 };
|
||||
|
||||
void
|
||||
|
@ -371,7 +371,7 @@ ok:
|
|||
|
||||
dns->wsi = lws_create_adopt_udp(context->vhost_list, ads, 53, 0,
|
||||
lws_async_dns_protocol.name, NULL,
|
||||
NULL, NULL, &retry_policy);
|
||||
NULL, NULL, &retry_policy, "asyncdns");
|
||||
if (!dns->wsi) {
|
||||
lwsl_err("%s: foreign socket adoption failed\n", __func__);
|
||||
return 1;
|
||||
|
|
|
@ -299,7 +299,7 @@ lws_dhcpc4_retry_conn(struct lws_sorted_usec_list *sul)
|
|||
68, LWS_CAUDP_PF_PACKET |
|
||||
LWS_CAUDP_BROADCAST,
|
||||
"lws-dhcp4client", (const char *)&r[1],
|
||||
NULL, NULL, &bo2);
|
||||
NULL, NULL, &bo2, "dhcpc");
|
||||
lwsl_debug("%s: created wsi_raw: %s\n", __func__, lws_wsi_tag(r->wsi_raw));
|
||||
if (!r->wsi_raw) {
|
||||
lwsl_err("%s: unable to create udp skt\n", __func__);
|
||||
|
|
|
@ -26,9 +26,8 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
static lws_fi_priv_t *
|
||||
lws_fi_lookup(lws_fi_ctx_t *fic, const char *name)
|
||||
lws_fi_lookup(const lws_fi_ctx_t *fic, const char *name)
|
||||
{
|
||||
lws_start_foreach_dll(struct lws_dll2 *, p, fic->fi_owner.head) {
|
||||
lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
|
||||
|
@ -42,58 +41,81 @@ lws_fi_lookup(lws_fi_ctx_t *fic, const char *name)
|
|||
}
|
||||
|
||||
int
|
||||
lws_fi(lws_fi_ctx_t *fic, const char *name)
|
||||
lws_fi(const lws_fi_ctx_t *fic, const char *name)
|
||||
{
|
||||
lws_fi_priv_t *pv = NULL;
|
||||
lws_fi_priv_t *pv;
|
||||
int n;
|
||||
|
||||
do {
|
||||
pv = lws_fi_lookup(fic, name);
|
||||
pv = lws_fi_lookup(fic, name);
|
||||
|
||||
if (pv) {
|
||||
int n;
|
||||
if (!pv)
|
||||
return 0;
|
||||
|
||||
switch (pv->fi.type) {
|
||||
case LWSFI_ALWAYS:
|
||||
switch (pv->fi.type) {
|
||||
case LWSFI_ALWAYS:
|
||||
goto inject;
|
||||
|
||||
case LWSFI_DETERMINISTIC:
|
||||
pv->fi.times++;
|
||||
if (pv->fi.times >= pv->fi.pre)
|
||||
if (pv->fi.times < pv->fi.pre + pv->fi.count)
|
||||
goto inject;
|
||||
return 0;
|
||||
|
||||
case LWSFI_DETERMINISTIC:
|
||||
pv->fi.times++;
|
||||
if (pv->fi.times >= pv->fi.pre)
|
||||
if (pv->fi.times < pv->fi.pre + pv->fi.count)
|
||||
goto inject;
|
||||
return 0;
|
||||
case LWSFI_PROBABILISTIC:
|
||||
if (lws_xos_percent((lws_xos_t *)&fic->xos, (int)pv->fi.pre))
|
||||
goto inject;
|
||||
return 0;
|
||||
|
||||
case LWSFI_PROBABILISTIC:
|
||||
pv->fi.times = (unsigned long)(pv->fi.times * 3) ^
|
||||
(unsigned long)lws_now_usecs();
|
||||
if ((uint16_t)pv->fi.times % 101 >= pv->fi.pre)
|
||||
goto inject;
|
||||
return 0;
|
||||
case LWSFI_PATTERN:
|
||||
case LWSFI_PATTERN_ALLOC:
|
||||
n = (int)((pv->fi.times++) % pv->fi.count);
|
||||
if (pv->fi.pattern[n >> 3] & (1 << (n & 7)))
|
||||
goto inject;
|
||||
|
||||
case LWSFI_PATTERN:
|
||||
n = (int)(pv->fi.times % pv->fi.pre);
|
||||
if (pv->fi.pattern[n >> 3] & (1 << (n & 7)))
|
||||
goto inject;
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fic = fic->parent;
|
||||
} while (fic);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
inject:
|
||||
lwsl_warn("%s: Injecting fault %s->%s\n", __func__, fic->name,
|
||||
pv->fi.name);
|
||||
lwsl_warn("%s: Injecting fault %s->%s\n", __func__,
|
||||
fic->name ? fic->name : "unk", pv->fi.name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
_lws_fi_user_wsi_fi(struct lws *wsi, const char *name)
|
||||
{
|
||||
return lws_fi(&wsi->fic, name);
|
||||
}
|
||||
|
||||
int
|
||||
_lws_fi_user_context_fi(struct lws_context *ctx, const char *name)
|
||||
{
|
||||
return lws_fi(&ctx->fic, name);
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
int
|
||||
_lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *name)
|
||||
{
|
||||
return lws_fi(&h->fic, name);
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
|
||||
int
|
||||
_lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *name)
|
||||
{
|
||||
return lws_fi(&h->fic, name);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi)
|
||||
{
|
||||
|
@ -130,7 +152,12 @@ lws_fi_remove(lws_fi_ctx_t *fic, const char *name)
|
|||
void
|
||||
lws_fi_import(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src)
|
||||
{
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, fic_src->fi_owner.head) {
|
||||
|
||||
/* inherit the PRNG seed for our context from source guy too */
|
||||
lws_xos_init(&fic_dest->xos, lws_xos((lws_xos_t *)&fic_src->xos));
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
|
||||
fic_src->fi_owner.head) {
|
||||
lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
|
||||
|
||||
lws_dll2_remove(&pv->list);
|
||||
|
@ -139,14 +166,210 @@ lws_fi_import(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src)
|
|||
} lws_end_foreach_dll_safe(p, p1);
|
||||
}
|
||||
|
||||
void
|
||||
lws_fi_destroy(lws_fi_ctx_t *fic)
|
||||
static void
|
||||
do_inherit(lws_fi_ctx_t *fic_dest, lws_fi_t *pfi, size_t trim)
|
||||
{
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, fic->fi_owner.head) {
|
||||
lws_fi_t fi = *pfi;
|
||||
|
||||
fi.name += trim;
|
||||
|
||||
lwsl_info("%s: %s: %s inherited as %s\n", __func__, fic_dest->name,
|
||||
pfi->name, fi.name);
|
||||
|
||||
if (fi.type == LWSFI_PATTERN_ALLOC) {
|
||||
fi.pattern = lws_malloc((size_t)((fi.count >> 3) + 1), __func__);
|
||||
if (!fi.pattern)
|
||||
return;
|
||||
memcpy((uint8_t *)fi.pattern, pfi->pattern,
|
||||
(size_t)((fi.count >> 3) + 1));
|
||||
}
|
||||
|
||||
lws_fi_add(fic_dest, &fi);
|
||||
}
|
||||
|
||||
void
|
||||
lws_fi_inherit_copy(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src,
|
||||
const char *scope, const char *value)
|
||||
{
|
||||
size_t sl = 0, vl = 0;
|
||||
|
||||
if (scope)
|
||||
sl = strlen(scope);
|
||||
|
||||
if (value)
|
||||
vl = strlen(value);
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
|
||||
fic_src->fi_owner.head) {
|
||||
lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
|
||||
size_t nl = strlen(pv->fi.name);
|
||||
|
||||
if (!scope)
|
||||
do_inherit(fic_dest, &pv->fi, 0);
|
||||
else
|
||||
if (nl > sl + 2 &&
|
||||
!strncmp(pv->fi.name, scope, sl) &&
|
||||
pv->fi.name[sl] == '/')
|
||||
do_inherit(fic_dest, &pv->fi, sl + 1);
|
||||
else {
|
||||
if (value && nl > sl + vl + 2 &&
|
||||
pv->fi.name[sl] == '=' &&
|
||||
!strncmp(pv->fi.name + sl + 1, value, vl) &&
|
||||
pv->fi.name[sl + 1 + vl] == '/')
|
||||
do_inherit(fic_dest, &pv->fi, sl + vl + 2);
|
||||
}
|
||||
|
||||
} lws_end_foreach_dll_safe(p, p1);
|
||||
}
|
||||
|
||||
void
|
||||
lws_fi_destroy(const lws_fi_ctx_t *fic)
|
||||
{
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
|
||||
fic->fi_owner.head) {
|
||||
lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
|
||||
|
||||
if (pv->fi.type == LWSFI_PATTERN_ALLOC && pv->fi.pattern) {
|
||||
lws_free((void *)pv->fi.pattern);
|
||||
pv->fi.pattern = NULL;
|
||||
}
|
||||
|
||||
lws_dll2_remove(&pv->list);
|
||||
lws_free(pv);
|
||||
|
||||
} lws_end_foreach_dll_safe(p, p1);
|
||||
}
|
||||
|
||||
enum {
|
||||
PARSE_NAME,
|
||||
PARSE_WHEN,
|
||||
PARSE_PC,
|
||||
PARSE_ENDBR
|
||||
};
|
||||
|
||||
void
|
||||
lws_fi_deserialize(lws_fi_ctx_t *fic, const char *sers)
|
||||
{
|
||||
struct lws_tokenize ts;
|
||||
lws_fi_t fi;
|
||||
char nm[64];
|
||||
int state = PARSE_NAME;
|
||||
|
||||
/*
|
||||
* Go through the comma-separated list of faults
|
||||
* creating them and adding to the lws_context info
|
||||
*/
|
||||
|
||||
lws_tokenize_init(&ts, sers, LWS_TOKENIZE_F_DOT_NONTERM |
|
||||
LWS_TOKENIZE_F_NO_INTEGERS |
|
||||
LWS_TOKENIZE_F_NO_FLOATS |
|
||||
LWS_TOKENIZE_F_EQUALS_NONTERM |
|
||||
LWS_TOKENIZE_F_SLASH_NONTERM |
|
||||
LWS_TOKENIZE_F_MINUS_NONTERM);
|
||||
ts.len = (unsigned int)strlen(sers);
|
||||
if (ts.len < 1 || ts.len > 10240)
|
||||
return;
|
||||
|
||||
do {
|
||||
ts.e = (int8_t)lws_tokenize(&ts);
|
||||
switch (ts.e) {
|
||||
case LWS_TOKZE_TOKEN:
|
||||
|
||||
if (state == PARSE_NAME) {
|
||||
/*
|
||||
* One fault to inject looks like, eg,
|
||||
*
|
||||
* vh=xxx/listenskt
|
||||
*/
|
||||
|
||||
memset(&fi, 0, sizeof(fi));
|
||||
|
||||
lws_strnncpy(nm, ts.token, ts.token_len, sizeof(nm));
|
||||
fi.name = nm;
|
||||
fi.type = LWSFI_ALWAYS;
|
||||
|
||||
lwsl_notice("%s: name %.*s\n", __func__, (int)ts.token_len, ts.token);
|
||||
|
||||
/* added later, potentially after (when) */
|
||||
break;
|
||||
}
|
||||
if (state == PARSE_WHEN) {
|
||||
/* it's either numeric or a pattern */
|
||||
|
||||
lwsl_notice("%s: when\n", __func__);
|
||||
|
||||
if (*ts.token == '.' || *ts.token == 'X') {
|
||||
uint8_t *pat;
|
||||
size_t n;
|
||||
|
||||
/*
|
||||
* pattern... we need to allocate it
|
||||
*/
|
||||
fi.type = LWSFI_PATTERN_ALLOC;
|
||||
pat = lws_zalloc((ts.token_len >> 3) + 1, __func__);
|
||||
if (!pat)
|
||||
return;
|
||||
fi.pattern = pat;
|
||||
fi.count = (uint64_t)ts.token_len;
|
||||
|
||||
for (n = 0; n < ts.token_len; n++)
|
||||
if (ts.token[n] == 'X')
|
||||
pat[n >> 3] = (uint8_t)(
|
||||
pat[n >> 3] | (1 << (n & 7)));
|
||||
|
||||
lwsl_hexdump_notice(pat, (ts.token_len >> 3) + 1);
|
||||
|
||||
state = PARSE_ENDBR;
|
||||
break;
|
||||
}
|
||||
|
||||
fi.pre = (uint64_t)atoi(ts.token);
|
||||
lwsl_notice("%s: prob %d%%\n", __func__, (int)fi.pre);
|
||||
fi.type = LWSFI_PROBABILISTIC;
|
||||
state = PARSE_PC;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_TOKZE_DELIMITER:
|
||||
if (*ts.token == ',') {
|
||||
lws_fi_add(fic, &fi);
|
||||
state = PARSE_NAME;
|
||||
break;
|
||||
}
|
||||
if (*ts.token == '(') {
|
||||
lwsl_notice("%s: (\n", __func__);
|
||||
if (state != PARSE_NAME) {
|
||||
lwsl_err("%s: misplaced (\n", __func__);
|
||||
return;
|
||||
}
|
||||
state = PARSE_WHEN;
|
||||
break;
|
||||
}
|
||||
if (*ts.token == ')') {
|
||||
if (state != PARSE_ENDBR) {
|
||||
lwsl_err("%s: misplaced )\n", __func__);
|
||||
return;
|
||||
}
|
||||
state = PARSE_NAME;
|
||||
break;
|
||||
}
|
||||
if (*ts.token == '%') {
|
||||
if (state != PARSE_PC) {
|
||||
lwsl_err("%s: misplaced %%\n", __func__);
|
||||
return;
|
||||
}
|
||||
state = PARSE_ENDBR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_TOKZE_ENDED:
|
||||
lws_fi_add(fic, &fi);
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} while (ts.e > 0);
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ lws_ntpc_retry_conn(struct lws_sorted_usec_list *sul)
|
|||
v->retry_count_write = 0;
|
||||
v->wsi_udp = lws_create_adopt_udp(v->vhost, v->ntp_server_ads, 123, 0,
|
||||
v->protocol->name, NULL, NULL, NULL,
|
||||
&bo2);
|
||||
&bo2, "ntpclient");
|
||||
lwsl_debug("%s: created wsi_udp: %s\n", __func__, lws_wsi_tag(v->wsi_udp));
|
||||
if (!v->wsi_udp) {
|
||||
lwsl_err("%s: unable to create udp skt\n", __func__);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* lws-api-test-lws_dsh
|
||||
*
|
||||
* Written in 2010-2019 by Andy Green <andy@warmcat.com>
|
||||
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
|
@ -252,7 +252,7 @@ test4(void)
|
|||
memset(blob, 0, sizeof(blob));
|
||||
|
||||
/*
|
||||
* test 1: use up whole free list, then recover and alloc something
|
||||
* test 4: use up whole free list, then recover and alloc something
|
||||
* else
|
||||
*/
|
||||
|
||||
|
@ -327,6 +327,92 @@ bail:
|
|||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
test5(void)
|
||||
{
|
||||
struct lws_dsh *dsh;
|
||||
unsigned int budget;
|
||||
uint8_t blob[4096];
|
||||
lws_xos_t xos;
|
||||
size_t size;
|
||||
void *a1;
|
||||
|
||||
memset(blob, 0, sizeof(blob));
|
||||
lws_xos_init(&xos, 0x123456789abcdef0ull);
|
||||
|
||||
budget = (unsigned int)(lws_xos(&xos) % 4000) + 4000;
|
||||
|
||||
lwsl_notice("%s: budget %u\n", __func__, budget);
|
||||
|
||||
|
||||
/*
|
||||
* test 5: PRNG-based spamming and erratic bidi draining
|
||||
*/
|
||||
|
||||
dsh = lws_dsh_create(NULL, 409600, 2);
|
||||
if (!dsh) {
|
||||
lwsl_err("%s: Failed to create dsh\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
if (lws_xos_percent(&xos, 60)) {
|
||||
/* kind 0 is going to try to write */
|
||||
|
||||
size = (size_t)((lws_xos(&xos) & 127) + 1);
|
||||
|
||||
if (!lws_dsh_alloc_tail(dsh, 0, blob, size, NULL, 0))
|
||||
lwsl_notice("%s: kind 0 alloc %d\n", __func__, (int)size);
|
||||
}
|
||||
|
||||
if (lws_xos_percent(&xos, 80)) {
|
||||
/* kind 1 is going to try to write */
|
||||
|
||||
size = (size_t)((lws_xos(&xos) & 127) + 1);
|
||||
|
||||
if (!lws_dsh_alloc_tail(dsh, 1, blob, size, NULL, 0))
|
||||
lwsl_notice("%s: kind 1 alloc %d\n", __func__, (int)size);
|
||||
}
|
||||
|
||||
if (lws_xos_percent(&xos, 40)) {
|
||||
/* kind 0 is going to try to read */
|
||||
|
||||
while (!lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
||||
lwsl_notice("%s: kind 0 read %d\n", __func__, (int)size);
|
||||
lws_dsh_free(&a1);
|
||||
}
|
||||
}
|
||||
|
||||
if (lws_xos_percent(&xos, 30)) {
|
||||
/* kind 1 is going to try to read */
|
||||
|
||||
while (!lws_dsh_get_head(dsh, 1, &a1, &size)) {
|
||||
lwsl_notice("%s: kind 1 read %d\n", __func__, (int)size);
|
||||
lws_dsh_free(&a1);
|
||||
}
|
||||
}
|
||||
|
||||
} while (budget--);
|
||||
|
||||
while (!lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
||||
lwsl_notice("%s: kind 0 read %d\n", __func__, (int)size);
|
||||
lws_dsh_free(&a1);
|
||||
}
|
||||
|
||||
while (!lws_dsh_get_head(dsh, 1, &a1, &size)) {
|
||||
lwsl_notice("%s: kind 1 read %d\n", __func__, (int)size);
|
||||
lws_dsh_free(&a1);
|
||||
}
|
||||
|
||||
lws_dsh_describe(dsh, "test dsh end state");
|
||||
|
||||
lws_dsh_destroy(&dsh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
|
@ -355,6 +441,10 @@ int main(int argc, const char **argv)
|
|||
lwsl_user("%s: test4: %d\n", __func__, n);
|
||||
ret |= n;
|
||||
|
||||
n = test5();
|
||||
lwsl_user("%s: test5: %d\n", __func__, n);
|
||||
ret |= n;
|
||||
|
||||
lwsl_user("Completed: %s\n", ret ? "FAIL" : "PASS");
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -794,8 +794,7 @@ done:
|
|||
return 0;
|
||||
|
||||
bail:
|
||||
if (test2())
|
||||
return 1;
|
||||
|
||||
lwsl_user("Completed: FAIL\n");
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* lws-api-test-lws_tokenize
|
||||
*
|
||||
* Written in 2010-2020 by Andy Green <andy@warmcat.com>
|
||||
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
|
@ -173,6 +173,10 @@ struct expected expected1[] = {
|
|||
expected17[] = {
|
||||
{ LWS_TOKZE_TOKEN, "hello", 5 },
|
||||
{ LWS_TOKZE_ENDED, "", 0 },
|
||||
},
|
||||
expected18[] = {
|
||||
{ LWS_TOKZE_TOKEN, "x=y", 3 },
|
||||
{ LWS_TOKZE_ENDED, "", 0 },
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -253,6 +257,10 @@ struct tests tests[] = {
|
|||
{
|
||||
"# comment1\r\nhello #comment2\r\n#comment3", expected17,
|
||||
LWS_ARRAY_SIZE(expected17), LWS_TOKENIZE_F_HASH_COMMENT
|
||||
},
|
||||
{
|
||||
"x=y", expected18,
|
||||
LWS_ARRAY_SIZE(expected18), LWS_TOKENIZE_F_EQUALS_NONTERM
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
project(lws-minimal-http-client-fi C)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
find_package(libwebsockets CONFIG REQUIRED)
|
||||
list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
|
||||
include(CheckCSourceCompiles)
|
||||
include(LwsCheckRequirements)
|
||||
|
||||
set(SAMP lws-minimal-http-client-fi)
|
||||
set(SRCS minimal-http-client.c)
|
||||
|
||||
set(requirements 1)
|
||||
require_lws_config(LWS_ROLE_H1 1 requirements)
|
||||
require_lws_config(LWS_WITH_CLIENT 1 requirements)
|
||||
require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
|
||||
require_lws_config(LWS_WITH_SYS_FAULT_INJECTION 1 requirements)
|
||||
|
||||
if (requirements)
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
# if (LWS_CTEST_INTERNET_AVAILABLE)
|
||||
# add_test(NAME http-client-warmcat COMMAND lws-minimal-http-client )
|
||||
# add_test(NAME http-client-warmcat-h1 COMMAND lws-minimal-http-client --h1)
|
||||
# set_tests_properties(http-client-warmcat
|
||||
# http-client-warmcat-h1
|
||||
# PROPERTIES
|
||||
# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client
|
||||
# TIMEOUT 20)
|
||||
#
|
||||
#endif()
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
|
||||
endif()
|
||||
endif()
|
|
@ -1,76 +0,0 @@
|
|||
# lws minimal http client
|
||||
|
||||
The application goes to either https://warmcat.com or
|
||||
https://localhost:7681 (with `-l` option) and receives the page data.
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
Commandline option|Meaning
|
||||
---|---
|
||||
-d <loglevel>|Debug verbosity in decimal, eg, -d15
|
||||
-l| Connect to https://localhost:7681 and accept selfsigned cert
|
||||
--h1|Specify http/1.1 only using ALPN, rejects h2 even if server supports it
|
||||
--server <name>|set server name to connect to
|
||||
-k|Apply tls option LCCSCF_ALLOW_INSECURE
|
||||
-j|Apply tls option LCCSCF_ALLOW_SELFSIGNED
|
||||
-m|Apply tls option LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
|
||||
-e|Apply tls option LCCSCF_ALLOW_EXPIRED
|
||||
-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
|
||||
--nossl| disable ssl connection
|
||||
--user <username>| Set Basic Auth username
|
||||
--password <password> | Set Basic Auth password
|
||||
|
||||
```
|
||||
$ ./lws-minimal-http-client
|
||||
[2018/03/04 14:43:20:8562] USER: LWS minimal http client
|
||||
[2018/03/04 14:43:20:8571] NOTICE: Creating Vhost 'default' port -1, 1 protocols, IPv6 on
|
||||
[2018/03/04 14:43:20:8616] NOTICE: created client ssl context for default
|
||||
[2018/03/04 14:43:20:8617] NOTICE: lws_client_connect_2: 0x1814dc0: address warmcat.com
|
||||
[2018/03/04 14:43:21:1496] NOTICE: lws_client_connect_2: 0x1814dc0: address warmcat.com
|
||||
[2018/03/04 14:43:22:0154] NOTICE: lws_client_interpret_server_handshake: incoming content length 26520
|
||||
[2018/03/04 14:43:22:0154] NOTICE: lws_client_interpret_server_handshake: client connection up
|
||||
[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
|
||||
[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
|
||||
[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
|
||||
[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
|
||||
[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
|
||||
[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
|
||||
[2018/03/04 14:43:22:3022] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
|
||||
[2018/03/04 14:43:22:3022] USER: RECEIVE_CLIENT_HTTP_READ: read 974
|
||||
[2018/03/04 14:43:22:3022] NOTICE: lws_http_client_read: transaction completed says -1
|
||||
[2018/03/04 14:43:23:3042] USER: Completed
|
||||
```
|
||||
|
||||
You can also test the client Basic Auth support against the http-server/minimal-http-server-basicauth
|
||||
example. In one console window run the server and in the other
|
||||
|
||||
```
|
||||
$ lws-minimal-http-client -l --nossl --path /secret/index.html --user user --password password
|
||||
```
|
||||
|
||||
The Basic Auth credentials for the test server are literally username "user" and password "password".
|
||||
|
|
@ -1,346 +0,0 @@
|
|||
/*
|
||||
* lws-minimal-http-client
|
||||
*
|
||||
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* This demonstrates the a minimal http client using lws.
|
||||
*
|
||||
* It visits https://warmcat.com/ and receives the html page there. You
|
||||
* can dump the page data by changing the #if 0 below.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
static int interrupted, bad = 1, status;
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
static int long_poll;
|
||||
#endif
|
||||
static struct lws *client_wsi;
|
||||
static const char *ba_user, *ba_password;
|
||||
|
||||
static const lws_retry_bo_t retry = {
|
||||
.secs_since_valid_ping = 3,
|
||||
.secs_since_valid_hangup = 10,
|
||||
};
|
||||
|
||||
static int
|
||||
callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
switch (reason) {
|
||||
|
||||
/* because we are protocols[0] ... */
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
|
||||
in ? (char *)in : "(null)");
|
||||
interrupted = 1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
lws_get_peer_simple(wsi, buf, sizeof(buf));
|
||||
status = (int)lws_http_client_http_response(wsi);
|
||||
|
||||
lwsl_user("Connected to %s, http response: %d\n",
|
||||
buf, status);
|
||||
}
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (long_poll) {
|
||||
lwsl_user("%s: Client entering long poll mode\n", __func__);
|
||||
lws_h2_client_stream_long_poll_rxonly(wsi);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_BASIC_AUTH)
|
||||
|
||||
/* you only need this if you need to do Basic Auth */
|
||||
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
|
||||
{
|
||||
unsigned char **p = (unsigned char **)in, *end = (*p) + len;
|
||||
char b[128];
|
||||
|
||||
if (!ba_user || !ba_password)
|
||||
break;
|
||||
|
||||
if (lws_http_basic_auth_gen(ba_user, ba_password, b, sizeof(b)))
|
||||
break;
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION,
|
||||
(unsigned char *)b, (int)strlen(b), p, end))
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* chunks of chunked content, with header removed */
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
||||
lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (long_poll) {
|
||||
char dotstar[128];
|
||||
lws_strnncpy(dotstar, (const char *)in, len,
|
||||
sizeof(dotstar));
|
||||
lwsl_notice("long poll rx: %d '%s'\n", (int)len,
|
||||
dotstar);
|
||||
}
|
||||
#endif
|
||||
#if 0 /* enable to dump the html */
|
||||
{
|
||||
const char *p = in;
|
||||
|
||||
while (len--)
|
||||
if (*p < 0x7f)
|
||||
putchar(*p++);
|
||||
else
|
||||
putchar('.');
|
||||
}
|
||||
#endif
|
||||
return 0; /* don't passthru */
|
||||
|
||||
/* uninterpreted http content */
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
|
||||
{
|
||||
char buffer[1024 + LWS_PRE];
|
||||
char *px = buffer + LWS_PRE;
|
||||
int lenx = sizeof(buffer) - LWS_PRE;
|
||||
|
||||
if (lws_http_client_read(wsi, &px, &lenx) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0; /* don't passthru */
|
||||
|
||||
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
|
||||
lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
|
||||
interrupted = 1;
|
||||
bad = status != 200;
|
||||
lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
|
||||
interrupted = 1;
|
||||
bad = status != 200;
|
||||
lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return lws_callback_http_dummy(wsi, reason, user, in, len);
|
||||
}
|
||||
|
||||
static const struct lws_protocols protocols[] = {
|
||||
{
|
||||
"http",
|
||||
callback_http,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{ NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
sigint_handler(int sig)
|
||||
{
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
struct args {
|
||||
int argc;
|
||||
const char **argv;
|
||||
};
|
||||
|
||||
static const lws_fi_t fi = {
|
||||
.name = "cliwsi.dnsfail",
|
||||
.type = LWSFI_ALWAYS
|
||||
};
|
||||
|
||||
static int
|
||||
make_client_connection(struct lws_context *context)
|
||||
{
|
||||
struct lws_client_connect_info i;
|
||||
struct args *a = lws_context_user(context);
|
||||
lws_fi_ctx_t fic;
|
||||
const char *p;
|
||||
|
||||
memset(&fic, 0, sizeof(fic));
|
||||
lws_fi_add(&fic, &fi);
|
||||
|
||||
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
|
||||
i.context = context;
|
||||
i.fi = &fic;
|
||||
|
||||
if (!lws_cmdline_option(a->argc, a->argv, "-n")) {
|
||||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
/* requires h2 */
|
||||
if (lws_cmdline_option(a->argc, a->argv, "--long-poll")) {
|
||||
lwsl_user("%s: long poll mode\n", __func__);
|
||||
long_poll = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-l")) {
|
||||
i.port = 7681;
|
||||
i.address = "localhost";
|
||||
i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
|
||||
} else {
|
||||
i.port = 443;
|
||||
i.address = "warmcat.com";
|
||||
}
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "--nossl"))
|
||||
i.ssl_connection = 0;
|
||||
|
||||
i.ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
|
||||
LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
|
||||
|
||||
i.alpn = "h2";
|
||||
if (lws_cmdline_option(a->argc, a->argv, "--h1"))
|
||||
i.alpn = "http/1.1";
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "--h2-prior-knowledge"))
|
||||
i.ssl_connection |= LCCSCF_H2_PRIOR_KNOWLEDGE;
|
||||
|
||||
if ((p = lws_cmdline_option(a->argc, a->argv, "-p")))
|
||||
i.port = atoi(p);
|
||||
|
||||
if ((p = lws_cmdline_option(a->argc, a->argv, "--user")))
|
||||
ba_user = p;
|
||||
if ((p = lws_cmdline_option(a->argc, a->argv, "--password")))
|
||||
ba_password = p;
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-j"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-k"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_INSECURE;
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-m"))
|
||||
i.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-e"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_EXPIRED;
|
||||
|
||||
if ((p = lws_cmdline_option(a->argc, a->argv, "-f"))) {
|
||||
i.ssl_connection |= LCCSCF_H2_MANUAL_RXFLOW;
|
||||
i.manual_initial_tx_credit = atoi(p);
|
||||
lwsl_notice("%s: manual peer tx credit %d\n", __func__,
|
||||
i.manual_initial_tx_credit);
|
||||
}
|
||||
|
||||
/* the default validity check is 5m / 5m10s... -v = 3s / 10s */
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-v"))
|
||||
i.retry_and_idle_policy = &retry;
|
||||
|
||||
if ((p = lws_cmdline_option(a->argc, a->argv, "--server")))
|
||||
i.address = p;
|
||||
|
||||
if ((p = lws_cmdline_option(a->argc, a->argv, "--path")))
|
||||
i.path = p;
|
||||
else
|
||||
i.path = "/";
|
||||
|
||||
i.host = i.address;
|
||||
i.origin = i.address;
|
||||
i.method = "GET";
|
||||
|
||||
i.protocol = protocols[0].name;
|
||||
i.pwsi = &client_wsi;
|
||||
|
||||
return !lws_client_connect_via_info(&i);
|
||||
}
|
||||
|
||||
static int
|
||||
system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
|
||||
int current, int target)
|
||||
{
|
||||
struct lws_context *context = mgr->parent;
|
||||
|
||||
if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
|
||||
return 0;
|
||||
|
||||
lwsl_info("%s: operational\n", __func__);
|
||||
|
||||
make_client_connection(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
lws_state_notify_link_t notifier = { {0}, system_notify_cb, "app" };
|
||||
lws_state_notify_link_t *na[] = { ¬ifier, NULL };
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
struct args args;
|
||||
int n = 0;
|
||||
// uint8_t memcert[4096];
|
||||
|
||||
args.argc = argc;
|
||||
args.argv = argv;
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
lws_cmdline_option_handle_builtin(argc, argv, &info);
|
||||
|
||||
lwsl_user("LWS minimal http client [-d<verbosity>] [-l] [--h1]\n");
|
||||
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
|
||||
info.protocols = protocols;
|
||||
info.user = &args;
|
||||
info.register_notifier_list = na;
|
||||
info.connect_timeout_secs = 30;
|
||||
|
||||
/*
|
||||
* since we know this lws context is only ever going to be used with
|
||||
* one client wsis / fds / sockets at a time, let lws know it doesn't
|
||||
* have to use the default allocations for fd tables up to ulimit -n.
|
||||
* It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
|
||||
* will use.
|
||||
*/
|
||||
info.fd_limit_per_thread = 1 + 1 + 1;
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
|
||||
/*
|
||||
* OpenSSL uses the system trust store. mbedTLS has to be told which
|
||||
* CA to trust explicitly.
|
||||
*/
|
||||
info.client_ssl_ca_filepath = "./warmcat.com.cer";
|
||||
#endif
|
||||
#if 0
|
||||
n = open("./warmcat.com.cer", O_RDONLY);
|
||||
if (n >= 0) {
|
||||
info.client_ssl_ca_mem_len = read(n, memcert, sizeof(memcert));
|
||||
info.client_ssl_ca_mem = memcert;
|
||||
close(n);
|
||||
n = 0;
|
||||
memcert[info.client_ssl_ca_mem_len++] = '\0';
|
||||
}
|
||||
#endif
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (n >= 0 && !interrupted)
|
||||
n = lws_service(context, 0);
|
||||
|
||||
lws_context_destroy(context);
|
||||
lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
|
||||
|
||||
return bad;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -8,16 +8,37 @@ include(LwsCheckRequirements)
|
|||
set(SAMP lws-minimal-http-client)
|
||||
set(SRCS minimal-http-client.c)
|
||||
|
||||
set(has_fault_injection 1)
|
||||
set(has_h2 1)
|
||||
set(has_plugins 1)
|
||||
set(has_ss_policy_parse 1)
|
||||
set(has_no_system_vhost 1)
|
||||
set(has_async_dns 1)
|
||||
|
||||
set(requirements 1)
|
||||
|
||||
require_lws_config(LWS_ROLE_H1 1 requirements)
|
||||
require_lws_config(LWS_WITH_CLIENT 1 requirements)
|
||||
require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
|
||||
|
||||
require_lws_config(LWS_ROLE_H2 1 has_h2)
|
||||
require_lws_config(LWS_WITH_SYS_FAULT_INJECTION 1 has_fault_injection)
|
||||
require_lws_config(LWS_WITH_EVLIB_PLUGINS 1 has_plugins)
|
||||
require_lws_config(LWS_WITH_EVENT_LIBS 1 has_plugins)
|
||||
|
||||
require_lws_config(LWS_WITH_SECURE_STREAMS 1 has_ss_policy_parse)
|
||||
require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 has_ss_policy_parse)
|
||||
|
||||
require_lws_config(LWS_WITH_SYS_ASYNC_DNS 0 has_no_system_vhost)
|
||||
require_lws_config(LWS_WITH_SYS_NTPCLIENT 0 has_no_system_vhost)
|
||||
require_lws_config(LWS_WITH_SYS_DHCP_CLIENT 0 has_no_system_vhost)
|
||||
|
||||
require_lws_config(LWS_WITH_SYS_ASYNC_DNS 1 has_async_dns)
|
||||
|
||||
if (requirements)
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
find_program(VALGRIND "valgrind")
|
||||
|
||||
sai_resource(warmcat_conns 1 40 http_client_warmcat)
|
||||
|
||||
|
@ -27,15 +48,102 @@ if (requirements)
|
|||
add_test(NAME http-client-warmcat COMMAND lws-minimal-http-client )
|
||||
list(APPEND mytests http-client-warmcat)
|
||||
endif()
|
||||
|
||||
|
||||
add_test(NAME http-client-warmcat-h1 COMMAND lws-minimal-http-client --h1)
|
||||
set_tests_properties(${mytests} PROPERTIES
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client
|
||||
TIMEOUT 20)
|
||||
|
||||
if (has_fault_injection)
|
||||
|
||||
# creation related faults
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx1)
|
||||
add_test(NAME http-client-fi-ctx1 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail1")
|
||||
|
||||
# if (has_plugins)
|
||||
# !!! need to actually select an available evlib plugin to trigger this
|
||||
# list(APPEND mytests http-client-fi-pi)
|
||||
# add_test(NAME http-client-fi-pi COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_plugin_init")
|
||||
# endif()
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx2)
|
||||
add_test(NAME http-client-fi-ctx2 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_sel")
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx3)
|
||||
add_test(NAME http-client-fi-ctx3 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_oom_ctx")
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx4)
|
||||
add_test(NAME http-client-fi-ctx4 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_privdrop")
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx5)
|
||||
add_test(NAME http-client-fi-ctx5 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_maxfds")
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx6)
|
||||
add_test(NAME http-client-fi-ctx6 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_oom_fds")
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx7)
|
||||
add_test(NAME http-client-fi-ctx7 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_plat_init")
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx8)
|
||||
add_test(NAME http-client-fi-ctx8 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_init")
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx9)
|
||||
add_test(NAME http-client-fi-ctx9 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_pt")
|
||||
|
||||
if (NOT has_no_system_vhost)
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx10)
|
||||
add_test(NAME http-client-fi-ctx10 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_sys_vh")
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx11)
|
||||
add_test(NAME http-client-fi-ctx11 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_sys_vh_init")
|
||||
|
||||
endif()
|
||||
|
||||
list(APPEND mytests http-client-fi-ctx12)
|
||||
add_test(NAME http-client-fi-ctx12 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_def_vh")
|
||||
|
||||
|
||||
list(APPEND mytests http-client-fi-vh1)
|
||||
add_test(NAME http-client-fi-vh1 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_oom")
|
||||
|
||||
list(APPEND mytests http-client-fi-vh2)
|
||||
add_test(NAME http-client-fi-vh2 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_pcols_oom")
|
||||
|
||||
list(APPEND mytests http-client-fi-vh3)
|
||||
add_test(NAME http-client-fi-vh3 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_ssl_srv")
|
||||
|
||||
list(APPEND mytests http-client-fi-vh4)
|
||||
add_test(NAME http-client-fi-vh4 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_ssl_cli")
|
||||
|
||||
list(APPEND mytests http-client-fi-vh5)
|
||||
add_test(NAME http-client-fi-vh5 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_srv_init")
|
||||
|
||||
|
||||
list(APPEND mytests http-client-fi-dnsfail)
|
||||
add_test(NAME http-client-fi-dnsfail COMMAND lws-minimal-http-client --expected-exit 3 --fault-injection "wsi=user/dnsfail")
|
||||
|
||||
if (has_async_dns)
|
||||
list(APPEND mytests http-client-fi-connfail)
|
||||
add_test(NAME http-client-fi-connfail COMMAND lws-minimal-http-client --expected-exit 3 --fault-injection "wsi=user/connfail")
|
||||
else()
|
||||
list(APPEND mytests http-client-fi-connfail)
|
||||
add_test(NAME http-client-fi-connfail COMMAND lws-minimal-http-client --expected-exit 2 --fault-injection "wsi=user/connfail")
|
||||
endif()
|
||||
|
||||
list(APPEND mytests http-client-fi-user-est-fail)
|
||||
add_test(NAME http-client-fi-user-est-fail COMMAND lws-minimal-http-client --expected-exit 3 --fault-injection "wsi/user_reject_at_est")
|
||||
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
if (DEFINED ENV{SAI_OVN})
|
||||
set_tests_properties(${mytests} PROPERTIES
|
||||
FIXTURES_REQUIRED "res_http_client_warmcat")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
|
||||
in ? (char *)in : "(null)");
|
||||
interrupted = 1;
|
||||
bad = 3; /* connection failed before we could make connection */
|
||||
lws_cancel_service(lws_get_context(wsi));
|
||||
|
||||
#if defined(LWS_WITH_CONMON)
|
||||
|
@ -97,6 +98,10 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
lws_h2_client_stream_long_poll_rxonly(wsi);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lws_fi_user_wsi_fi(wsi, "user_reject_at_est"))
|
||||
return -1;
|
||||
|
||||
break;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_BASIC_AUTH)
|
||||
|
@ -132,17 +137,10 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
dotstar);
|
||||
}
|
||||
#endif
|
||||
#if 0 /* enable to dump the html */
|
||||
{
|
||||
const char *p = in;
|
||||
|
||||
while (len--)
|
||||
if (*p < 0x7f)
|
||||
putchar(*p++);
|
||||
else
|
||||
putchar('.');
|
||||
}
|
||||
#if 0
|
||||
lwsl_hexdump_notice(in, len);
|
||||
#endif
|
||||
|
||||
return 0; /* don't passthru */
|
||||
|
||||
/* uninterpreted http content */
|
||||
|
@ -152,6 +150,9 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
char *px = buffer + LWS_PRE;
|
||||
int lenx = sizeof(buffer) - LWS_PRE;
|
||||
|
||||
if (lws_fi_user_wsi_fi(wsi, "user_reject_at_rx"))
|
||||
return -1;
|
||||
|
||||
if (lws_http_client_read(wsi, &px, &lenx) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
@ -304,8 +305,18 @@ system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
|
|||
|
||||
i.protocol = protocols[0].name;
|
||||
i.pwsi = &client_wsi;
|
||||
i.fi_wsi_name = "user";
|
||||
|
||||
return !lws_client_connect_via_info(&i);
|
||||
if (!lws_client_connect_via_info(&i)) {
|
||||
lwsl_err("Client creation failed\n");
|
||||
interrupted = 1;
|
||||
bad = 2; /* could not even start client connection */
|
||||
lws_cancel_service(context);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
|
@ -314,8 +325,9 @@ int main(int argc, const char **argv)
|
|||
lws_state_notify_link_t *na[] = { ¬ifier, NULL };
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
int n = 0, expected = 0;
|
||||
struct args args;
|
||||
int n = 0;
|
||||
const char *p;
|
||||
// uint8_t memcert[4096];
|
||||
|
||||
args.argc = argc;
|
||||
|
@ -334,7 +346,7 @@ int main(int argc, const char **argv)
|
|||
info.protocols = protocols;
|
||||
info.user = &args;
|
||||
info.register_notifier_list = na;
|
||||
info.connect_timeout_secs = 30;
|
||||
info.connect_timeout_secs = 30;
|
||||
|
||||
/*
|
||||
* since we know this lws context is only ever going to be used with
|
||||
|
@ -365,14 +377,24 @@ int main(int argc, const char **argv)
|
|||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
bad = 5;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
while (n >= 0 && !interrupted)
|
||||
n = lws_service(context, 0);
|
||||
|
||||
lws_context_destroy(context);
|
||||
lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
|
||||
|
||||
return bad;
|
||||
bail:
|
||||
if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
|
||||
expected = atoi(p);
|
||||
|
||||
if (bad == expected) {
|
||||
lwsl_user("Completed: OK (seen expected %d)\n", expected);
|
||||
return 0;
|
||||
} else
|
||||
lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -150,6 +150,9 @@ do_client_conn(void)
|
|||
i.origin = i.address;
|
||||
i.method = "GET";
|
||||
i.local_protocol_name = protocols[0].name;
|
||||
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
||||
i.fi_wsi_name = "user";
|
||||
#endif
|
||||
|
||||
if (!lws_client_connect_via_info(&i)) {
|
||||
lwsl_err("Client creation failed\n");
|
||||
|
|
|
@ -182,7 +182,8 @@ int main(int argc, const char **argv)
|
|||
* Create our own "foreign" UDP socket bound to 7681/udp
|
||||
*/
|
||||
if (!lws_create_adopt_udp(vhost, NULL, 7681, LWS_CAUDP_BIND,
|
||||
protocols[0].name, NULL, NULL, NULL, NULL)) {
|
||||
protocols[0].name, NULL, NULL, NULL, NULL,
|
||||
"user")) {
|
||||
lwsl_err("%s: foreign socket adoption failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
static int interrupted, bad = 1, port = 0 /* unix domain socket */;
|
||||
static const char *ibind = NULL; /* default to unix domain skt "proxy.ss.lws" */
|
||||
static lws_state_notify_link_t nl;
|
||||
static struct lws_context *context;
|
||||
|
||||
/*
|
||||
* We just define enough policy so it can fetch the latest one securely
|
||||
|
@ -233,41 +234,21 @@ static const lws_system_ops_t system_ops = {
|
|||
static void
|
||||
sigint_handler(int sig)
|
||||
{
|
||||
lwsl_notice("%s\n", __func__);
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
assert_bt(int sig)
|
||||
{
|
||||
#if defined(__APPLE__) || defined(__linux__)
|
||||
void *array[20];
|
||||
char **strings;
|
||||
int size, i;
|
||||
|
||||
size = backtrace (array, 10);
|
||||
strings = backtrace_symbols (array, size);
|
||||
if (!strings)
|
||||
return;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
printf("%s\n", strings[i]);
|
||||
|
||||
free (strings);
|
||||
#endif
|
||||
lws_cancel_service(context);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
const char *p;
|
||||
int n = 0;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
lws_cmdline_option_handle_builtin(argc, argv, &info);
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
signal(SIGABRT, assert_bt);
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
/* connect to ssproxy via UDS by default, else via tcp with this port */
|
||||
if ((p = lws_cmdline_option(argc, argv, "-p")))
|
||||
|
@ -278,11 +259,8 @@ int main(int argc, const char **argv)
|
|||
if ((p = lws_cmdline_option(argc, argv, "-i")))
|
||||
ibind = p;
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS secure streams Proxy [-d<verb>]\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
|
||||
info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
|
||||
LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
|
||||
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
|
@ -311,8 +289,9 @@ int main(int argc, const char **argv)
|
|||
|
||||
/* the event loop */
|
||||
|
||||
while (n >= 0 && !interrupted)
|
||||
do {
|
||||
n = lws_service(context, 0);
|
||||
} while (n >= 0 && !interrupted);
|
||||
|
||||
bad = 0;
|
||||
|
||||
|
|
|
@ -248,13 +248,18 @@ myss_state(void *userobj, void *sh, lws_ss_constate_t state,
|
|||
case LWSSSCS_ALL_RETRIES_FAILED:
|
||||
/* if we're out of retries, we want to close the app and FAIL */
|
||||
interrupted = 1;
|
||||
bad = 2;
|
||||
break;
|
||||
|
||||
case LWSSSCS_QOS_ACK_REMOTE:
|
||||
lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__);
|
||||
break;
|
||||
|
||||
case LWSSSCS_TIMEOUT:
|
||||
lwsl_notice("%s: LWSSSCS_TIMEOUT\n", __func__);
|
||||
/* if we're out of time */
|
||||
interrupted = 1;
|
||||
bad = 3;
|
||||
break;
|
||||
|
||||
case LWSSSCS_USER_BASE:
|
||||
|
@ -405,8 +410,8 @@ int main(int argc, const char **argv)
|
|||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
int n = 0, expected = 0;
|
||||
const char *p;
|
||||
int n = 0;
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
|
@ -475,7 +480,7 @@ int main(int argc, const char **argv)
|
|||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
#if !defined(LWS_SS_USE_SSPC)
|
||||
|
@ -520,7 +525,15 @@ int main(int argc, const char **argv)
|
|||
|
||||
lws_context_destroy(context);
|
||||
|
||||
lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
|
||||
bail:
|
||||
if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
|
||||
expected = atoi(p);
|
||||
|
||||
return bad;
|
||||
if (bad == expected) {
|
||||
lwsl_user("Completed: OK (seen expected %d)\n", expected);
|
||||
return 0;
|
||||
} else
|
||||
lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue