mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-30 00:00:16 +01:00
remove: lws_sequencer
lws_sequencer and lws_abstract were both false starts trying to do the functionality of secure streams. Since Secure Streams does a better job for both and there are no known out-of-tree users of them, let's remove them and focus on Secure Streams.
This commit is contained in:
parent
057d03997f
commit
f5edf9d75a
33 changed files with 5 additions and 3919 deletions
|
@ -154,7 +154,6 @@ if (NOT LWS_WITH_NETWORK)
|
|||
set(LWS_WITH_HTTP_STREAM_COMPRESSION 0)
|
||||
set(LWS_WITH_HTTP_BROTLI 0)
|
||||
set(LWS_WITH_POLL 0)
|
||||
set(LWS_WITH_SEQUENCER 0)
|
||||
set(LWS_ROLE_DBUS 0)
|
||||
set(LWS_WITH_LWS_DSH 0)
|
||||
set(LWS_WITH_THREADPOOL 0)
|
||||
|
|
|
@ -296,7 +296,6 @@ option(LWS_WITH_LEJP_CONF "With LEJP configuration parser as used by lwsws" OFF)
|
|||
option(LWS_WITH_ZLIB "Include zlib support (required for extensions)" OFF)
|
||||
option(LWS_WITH_BUNDLED_ZLIB "Use bundled zlib version (Windows only)" ${LWS_WITH_BUNDLED_ZLIB_DEFAULT})
|
||||
option(LWS_WITH_MINIZ "Use miniz instead of zlib" OFF)
|
||||
option(LWS_WITH_SEQUENCER "lws_seq_t support" OFF)
|
||||
option(LWS_WITH_EXTERNAL_POLL "Support external POLL integration using callback messages (not recommended)" OFF)
|
||||
option(LWS_WITH_LWS_DSH "Support lws_dsh_t Disordered Shared Heap" OFF)
|
||||
option(LWS_CLIENT_HTTP_PROXYING "Support external http proxies for client connections" ON)
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
# `struct lws_sequencer` introduction
|
||||
|
||||
Often a single network action like a client GET is just part of a
|
||||
larger series of actions, perhaps involving different connections.
|
||||
|
||||
Since lws operates inside an event loop, if the outer sequencing
|
||||
doesn't, it can be awkward to synchronize these steps with what's
|
||||
happening on the network with a particular connection on the event
|
||||
loop thread.
|
||||
|
||||

|
||||
|
||||
`struct lws_sequencer` provides a generic way to stage multi-step
|
||||
operations from inside the event loop. Because it participates
|
||||
in the event loop similar to a wsi, it always operates from the
|
||||
service thread context and can access structures that share the
|
||||
service thread without locking. It can also provide its own
|
||||
higher-level timeout handling.
|
||||
|
||||
Naturally you can have many of them running in the same event
|
||||
loop operating independently.
|
||||
|
||||
Sequencers themselves bind to a pt (per-thread) service thread,
|
||||
by default there's only one of these and it's the same as saying
|
||||
they bind to an `lws_context`. The sequencer callback may create
|
||||
wsi which in turn are bound to a vhost, but the sequencer itself
|
||||
is above all that.
|
||||
|
||||
## Sequencer timeouts
|
||||
|
||||
The sequencer additionally maintains its own second-resolution timeout
|
||||
checked by lws for the step being sequenced... this is independent of
|
||||
any lws wsi timeouts which tend to be set and reset for very short-term
|
||||
timeout protection inside one transaction.
|
||||
|
||||
The sequencer timeout operates separately and above any wsi timeout, and
|
||||
is typically only reset by the sequencer callback when it receives an
|
||||
event indicating a step completed or failed, or it sets up the next sequence
|
||||
step.
|
||||
|
||||
If the sequencer timeout expires, then the sequencer receives a queued
|
||||
`LWSSEQ_TIMED_OUT` message informing it, and it can take corrective action
|
||||
or schedule a retry of the step. This message is queued and sent normally
|
||||
under the service thread context and in order of receipt.
|
||||
|
||||
Unlike lws timeouts which force the wsi to close, the sequencer timeout
|
||||
only sends the message. This allows the timeout to be used to, eg, wait
|
||||
out a retry cooloff period and then start the retry when the
|
||||
`LWSSEQ_TIMED_OUT` is received, according to the state of the sequencer.
|
||||
|
||||
## Creating an `struct lws_sequencer`
|
||||
|
||||
```
|
||||
typedef struct lws_seq_info {
|
||||
struct lws_context *context; /* lws_context for seq */
|
||||
int tsi; /* thread service idx */
|
||||
size_t user_size; /* size of user alloc */
|
||||
void **puser; /* place ptr to user */
|
||||
lws_seq_event_cb cb; /* seq callback */
|
||||
const char *name; /* seq name */
|
||||
const lws_retry_bo_t *retry; /* retry policy */
|
||||
} lws_seq_info_t;
|
||||
```
|
||||
|
||||
```
|
||||
struct lws_sequencer *
|
||||
lws_sequencer_create(lws_seq_info_t *info);
|
||||
```
|
||||
|
||||
When created, in lws the sequencer objects are bound to a 'per-thread',
|
||||
which is by default the same as to say bound to the `lws_context`. You
|
||||
can tag them with an opaque user data pointer, and they are also bound to
|
||||
a user-specified callback which handles sequencer events
|
||||
|
||||
```
|
||||
typedef int (*lws_seq_event_cb)(struct lws_sequencer *seq, void *user_data,
|
||||
lws_seq_events_t event, void *data);
|
||||
```
|
||||
|
||||
`struct lws_sequencer` objects are private to lws and opaque to the user. A small
|
||||
set of apis lets you perform operations on the pointer returned by the
|
||||
create api.
|
||||
|
||||
## Queueing events on a sequencer
|
||||
|
||||
Each sequencer object can be passed "events", which are held on a per-sequencer
|
||||
queue and handled strictly in the order they arrived on subsequent event loops.
|
||||
`LWSSEQ_CREATED` and `LWSSEQ_DESTROYED` events are produced by lws reflecting
|
||||
the sequencer's lifecycle, but otherwise the event indexes have a user-defined
|
||||
meaning and are queued on the sequencer by user code for eventual consumption
|
||||
by user code in the sequencer callback.
|
||||
|
||||
Pending events are removed from the sequencer queues and sent to the sequencer
|
||||
callback from inside the event loop at a rate of one per event loop wait.
|
||||
|
||||
## Destroying sequencers
|
||||
|
||||
`struct lws_sequencer` objects are cleaned up during context destruction if they are
|
||||
still around.
|
||||
|
||||
Normally the sequencer callback receives a queued message that
|
||||
informs it that it's either failed at the current step, or succeeded and that
|
||||
was the last step, and requests that it should be destroyed by returning
|
||||
`LWSSEQ_RET_DESTROY` from the sequencer callback.
|
||||
|
||||
## Lifecycle considerations
|
||||
|
||||
Sequencers may spawn additional assets like client wsi as part of the sequenced
|
||||
actions... the lifecycle of the sequencer and the assets overlap but do not
|
||||
necessarily depend on each other... that is a wsi created by the sequencer may
|
||||
outlive the sequencer.
|
||||
|
||||
It's important therefore to detach assets from the sequencer and the sequencer
|
||||
from the assets when each step is over and the asset is "out of scope" for the
|
||||
sequencer. It doesn't necessarily mean closing the assets, just making sure
|
||||
pointers are invalidated. For example, if a client wsi held a pointer to the
|
||||
sequencer as its `.user_data`, when the wsi is out of scope for the sequencer
|
||||
it can set it to NULL, eg, `lws_set_wsi_user(wsi, NULL);`.
|
||||
|
||||
Under some conditions wsi may want to hang around a bit to see if there is a
|
||||
subsequent client wsi transaction they can be reused on. They will clean
|
||||
themselves up when they time out.
|
||||
|
||||
## Watching wsi lifecycle from a sequencer
|
||||
|
||||
When a sequencer is creating a wsi as part of its sequence, it will be very
|
||||
interested in lifecycle events. At client wsi creation time, the sequencer
|
||||
callback can set info->seq to itself in order to receive lifecycle messages
|
||||
about its wsi.
|
||||
|
||||
|message|meaning|
|
||||
|---|---|
|
||||
|`LWSSEQ_WSI_CONNECTED`|The wsi has become connected|
|
||||
|`LWSSEQ_WSI_CONN_FAIL`|The wsi has failed to connect|
|
||||
|`LWSSEQ_WSI_CONN_CLOSE`|The wsi had been connected, but has now closed|
|
||||
|
||||
By receiving these, the sequencer can understand when it should attempt
|
||||
reconnections or that it cannot progress the sequence.
|
||||
|
||||
When dealing with wsi that were created by the sequencer, they may close at
|
||||
any time, eg, be closed by the remote peer or an intermediary. The
|
||||
`LWSSEQ_WSI_CONN_CLOSE` message may have been queued but since they are
|
||||
strictly handled in the order they arrived, before it was
|
||||
handled an earlier message may want to cause some api to be called on
|
||||
the now-free()-d wsi. To detect this situation safely, there is a
|
||||
sequencer api `lws_sequencer_check_wsi()` which peeks the message
|
||||
buffer and returns nonzero if it later contains an `LWSSEQ_WSI_CONN_CLOSE`
|
||||
already.
|
||||
|
|
@ -54,7 +54,6 @@ extern "C" {
|
|||
/* place for one-shot opaque forward references */
|
||||
|
||||
typedef struct lws_context * lws_ctx_t;
|
||||
struct lws_sequencer;
|
||||
struct lws_dsh;
|
||||
|
||||
/*
|
||||
|
@ -664,7 +663,6 @@ struct lws;
|
|||
#include <libwebsockets/lws-lwsac.h>
|
||||
#include <libwebsockets/lws-fts.h>
|
||||
#include <libwebsockets/lws-diskcache.h>
|
||||
#include <libwebsockets/lws-sequencer.h>
|
||||
#include <libwebsockets/lws-secure-streams.h>
|
||||
#include <libwebsockets/lws-secure-streams-serialization.h>
|
||||
#include <libwebsockets/lws-secure-streams-policy.h>
|
||||
|
@ -672,11 +670,6 @@ struct lws;
|
|||
#include <libwebsockets/lws-secure-streams-transport-proxy.h>
|
||||
#include <libwebsockets/lws-jrpc.h>
|
||||
|
||||
#if !defined(LWS_PLAT_FREERTOS)
|
||||
#include <libwebsockets/abstract/abstract.h>
|
||||
|
||||
#include <libwebsockets/lws-test-sequencer.h>
|
||||
#endif
|
||||
#include <libwebsockets/lws-async-dns.h>
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These are used to optionally pass an array of index = C string, binary array,
|
||||
* or ulong tokens to the abstract transport or protocol. For example if it's
|
||||
* raw socket transport, then the DNS address to connect to and the port are
|
||||
* passed using these when the client created and bound to the transport.
|
||||
*/
|
||||
|
||||
typedef struct lws_token_map {
|
||||
union {
|
||||
const char *value;
|
||||
uint8_t *bvalue;
|
||||
unsigned long lvalue;
|
||||
} u;
|
||||
short name_index; /* 0 here indicates end of array */
|
||||
short length_or_zero;
|
||||
} lws_token_map_t;
|
||||
|
||||
/*
|
||||
* The indvidual protocols and transports define their own name_index-es which
|
||||
* are meaningful to them. Define index 0 globally as the end of an array of
|
||||
* them, and provide bases so user protocol and transport ones don't overlap.
|
||||
*/
|
||||
|
||||
enum {
|
||||
LTMI_END_OF_ARRAY,
|
||||
|
||||
LTMI_PROTOCOL_BASE = 2048,
|
||||
|
||||
LTMI_TRANSPORT_BASE = 4096
|
||||
};
|
||||
|
||||
struct lws_abs_transport;
|
||||
struct lws_abs_protocol;
|
||||
typedef struct lws_abs lws_abs_t;
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN const lws_token_map_t *
|
||||
lws_abs_get_token(const lws_token_map_t *token_map, short name_index);
|
||||
|
||||
/*
|
||||
* the combination of a protocol, transport, and token maps for each
|
||||
*/
|
||||
|
||||
typedef void lws_abs_transport_inst_t;
|
||||
typedef void lws_abs_protocol_inst_t;
|
||||
|
||||
/**
|
||||
* lws_abstract_alloc() - allocate and configure an lws_abs_t
|
||||
*
|
||||
* \param vhost: the struct lws_vhost to bind to
|
||||
* \param user: opaque user pointer
|
||||
* \param abstract_path: "protocol.transport" names
|
||||
* \param ap_tokens: tokens for protocol options
|
||||
* \param at_tokens: tokens for transport
|
||||
* \param seq: optional sequencer we should bind to, or NULL
|
||||
* \param opaque_user_data: data given in sequencer callback, if any
|
||||
*
|
||||
* Returns an allocated lws_abs_t pointer set up with the other arguments.
|
||||
*
|
||||
* Doesn't create a connection instance, just allocates the lws_abs_t and
|
||||
* sets it up with the arguments.
|
||||
*
|
||||
* Returns NULL is there's any problem.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN lws_abs_t *
|
||||
lws_abstract_alloc(struct lws_vhost *vhost, void *user,
|
||||
const char *abstract_path, const lws_token_map_t *ap_tokens,
|
||||
const lws_token_map_t *at_tokens, struct lws_sequencer *seq,
|
||||
void *opaque_user_data);
|
||||
|
||||
/**
|
||||
* lws_abstract_free() - free an allocated lws_abs_t
|
||||
*
|
||||
* \param pabs: pointer to the lws_abs_t * to free
|
||||
*
|
||||
* Frees and sets the pointer to NULL.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_abstract_free(lws_abs_t **pabs);
|
||||
|
||||
/**
|
||||
* lws_abs_bind_and_create_instance - use an abstract protocol and transport
|
||||
*
|
||||
* \param abs: the lws_abs_t describing the combination desired
|
||||
*
|
||||
* This instantiates an abstract protocol and abstract transport bound together.
|
||||
* A single heap allocation is made for the combination and the protocol and
|
||||
* transport creation ops are called on it. The ap_tokens and at_tokens
|
||||
* are consulted by the creation ops to decide the details of the protocol and
|
||||
* transport for the instance.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN lws_abs_t *
|
||||
lws_abs_bind_and_create_instance(const lws_abs_t *ai);
|
||||
|
||||
/**
|
||||
* lws_abs_destroy_instance() - destroys an instance
|
||||
*
|
||||
* \param ai: pointer to the ai pointer to destroy
|
||||
*
|
||||
* This is for destroying an instance created by
|
||||
* lws_abs_bind_and_create_instance() above.
|
||||
*
|
||||
* Calls the protocol and transport destroy operations on the instance, then
|
||||
* frees the combined allocation in one step. The pointer ai is set to NULL.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_abs_destroy_instance(lws_abs_t **ai);
|
||||
|
||||
/*
|
||||
* bring in all the protocols and transports definitions
|
||||
*/
|
||||
|
||||
#include <libwebsockets/abstract/protocols.h>
|
||||
#include <libwebsockets/abstract/transports.h>
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Information about how this protocol handles multiple use of connections.
|
||||
*
|
||||
* .flags of 0 indicates each connection must start with a fresh transport.
|
||||
*
|
||||
* Flags can be used to indicate the protocol itself supports different
|
||||
* kinds of multiple use. However the actual use or not of these may depend on
|
||||
* negotiation with the remote peer.
|
||||
*
|
||||
* LWS_AP_FLAG_PIPELINE_TRANSACTIONS: other instances can be queued on one
|
||||
* with an existing connection and get a
|
||||
* chance to "hot take over" the existing
|
||||
* transport in turn, like h1 keepalive
|
||||
* pipelining
|
||||
*
|
||||
* LWS_AP_FLAG_MUXABLE_STREAM: an existing connection can absorb more child
|
||||
* connections and mux them as separate child
|
||||
* streams ongoing, like h2
|
||||
*/
|
||||
|
||||
enum {
|
||||
LWS_AP_FLAG_PIPELINE_TRANSACTIONS = (1 << 0),
|
||||
LWS_AP_FLAG_MUXABLE_STREAM = (1 << 1),
|
||||
};
|
||||
|
||||
typedef struct lws_abs_protocol {
|
||||
const char *name;
|
||||
int alloc;
|
||||
int flags;
|
||||
|
||||
int (*create)(const struct lws_abs *ai);
|
||||
void (*destroy)(lws_abs_protocol_inst_t **d);
|
||||
int (*compare)(lws_abs_t *abs1, lws_abs_t *abs2);
|
||||
|
||||
/* events the transport invokes (handled by abstract protocol) */
|
||||
|
||||
int (*accept)(lws_abs_protocol_inst_t *d);
|
||||
int (*rx)(lws_abs_protocol_inst_t *d, const uint8_t *b, size_t l);
|
||||
int (*writeable)(lws_abs_protocol_inst_t *d, size_t budget);
|
||||
int (*closed)(lws_abs_protocol_inst_t *d);
|
||||
int (*heartbeat)(lws_abs_protocol_inst_t *d);
|
||||
|
||||
/* as parent, we get a notification a new child / queue entry
|
||||
* bound to us... this is the parent lws_abs_t as arg */
|
||||
int (*child_bind)(lws_abs_t *abs);
|
||||
} lws_abs_protocol_t;
|
||||
|
||||
/**
|
||||
* lws_abs_protocol_get_by_name() - returns a pointer to the named protocol ops
|
||||
*
|
||||
* \param name: the name of the abstract protocol
|
||||
*
|
||||
* Returns a pointer to the named protocol ops struct if available, otherwise
|
||||
* NULL.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN const lws_abs_protocol_t *
|
||||
lws_abs_protocol_get_by_name(const char *name);
|
||||
|
||||
/*
|
||||
* bring in public api pieces from protocols
|
||||
*/
|
||||
|
||||
#include <libwebsockets/abstract/protocols/smtp.h>
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
/** \defgroup smtp SMTP related functions
|
||||
* ##SMTP related functions
|
||||
* \ingroup lwsapi
|
||||
*
|
||||
* These apis let you communicate with a local SMTP server to send email from
|
||||
* lws. It handles all the SMTP sequencing and protocol actions.
|
||||
*
|
||||
* Your system should have postfix, sendmail or another MTA listening on port
|
||||
* 25 and able to send email using the "mail" commandline app. Usually distro
|
||||
* MTAs are configured for this by default.
|
||||
*
|
||||
* You can either use the abstract protocol layer directly, or instead use the
|
||||
* provided smtp sequencer... this takes care of creating the protocol
|
||||
* connections, and provides and email queue and retry management.
|
||||
*/
|
||||
//@{
|
||||
|
||||
#if defined(LWS_WITH_SMTP)
|
||||
|
||||
enum {
|
||||
LTMI_PSMTP_V_HELO = LTMI_PROTOCOL_BASE, /* u.value */
|
||||
|
||||
LTMI_PSMTP_V_LWS_SMTP_EMAIL_T, /* u.value */
|
||||
};
|
||||
|
||||
enum {
|
||||
LWS_SMTP_DISPOSITION_SENT,
|
||||
LWS_SMTP_DISPOSITION_FAILED,
|
||||
LWS_SMTP_DISPOSITION_FAILED_DESTROY
|
||||
};
|
||||
|
||||
typedef struct lws_smtp_sequencer_args {
|
||||
const char helo[32];
|
||||
struct lws_vhost *vhost;
|
||||
time_t retry_interval;
|
||||
time_t delivery_timeout;
|
||||
size_t email_queue_max;
|
||||
size_t max_content_size;
|
||||
} lws_smtp_sequencer_args_t;
|
||||
|
||||
typedef struct lws_smtp_sequencer lws_smtp_sequencer_t;
|
||||
typedef struct lws_smtp_email lws_smtp_email_t;
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN lws_smtp_sequencer_t *
|
||||
lws_smtp_sequencer_create(const lws_smtp_sequencer_args_t *args);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_smtp_sequencer_destroy(lws_smtp_sequencer_t *s);
|
||||
|
||||
typedef int (*lws_smtp_cb_t)(void *e, void *d, int disp, const void *b, size_t l);
|
||||
typedef struct lws_smtp_email lws_smtp_email_t;
|
||||
|
||||
/**
|
||||
* lws_smtpc_add_email() - Allocates and queues an email object
|
||||
*
|
||||
* \param s: smtp sequencer to queue on
|
||||
* \param payload: the email payload string, with headers and terminating .
|
||||
* \param payload_len: size in bytes of the payload string
|
||||
* \param sender: the sender name and email
|
||||
* \param recipient: the recipient name and email
|
||||
* \param data: opaque user data returned in the done callback
|
||||
* \param done: callback called when the email send succeeded or failed
|
||||
*
|
||||
* Allocates an email object and copies the payload, sender and recipient into
|
||||
* it and initializes it. Returns NULL if OOM, otherwise the allocated email
|
||||
* object.
|
||||
*
|
||||
* Because it copies the arguments into an allocated buffer, the original
|
||||
* arguments can be safely destroyed after calling this.
|
||||
*
|
||||
* The done() callback must free the email object. It doesn't have to free any
|
||||
* individual members.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_smtpc_add_email(lws_smtp_sequencer_t *s, const char *payload,
|
||||
size_t payload_len, const char *sender,
|
||||
const char *recipient, void *data, lws_smtp_cb_t done);
|
||||
|
||||
/**
|
||||
* lws_smtpc_free_email() - Add email to the list of ones being sent
|
||||
*
|
||||
* \param e: email to queue for sending on \p c
|
||||
*
|
||||
* Adds an email to the linked-list of emails to send
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_smtpc_free_email(lws_smtp_email_t *e);
|
||||
|
||||
|
||||
#endif
|
||||
//@}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstract transport ops
|
||||
*/
|
||||
|
||||
typedef struct lws_abs_transport {
|
||||
const char *name;
|
||||
int alloc;
|
||||
|
||||
int (*create)(lws_abs_t *abs);
|
||||
void (*destroy)(lws_abs_transport_inst_t **d);
|
||||
|
||||
/* check if the transport settings for these connections are the same */
|
||||
int (*compare)(lws_abs_t *abs1, lws_abs_t *abs2);
|
||||
|
||||
/* events the abstract protocol invokes (handled by transport) */
|
||||
|
||||
int (*tx)(lws_abs_transport_inst_t *d, uint8_t *buf, size_t len);
|
||||
int (*client_conn)(const lws_abs_t *abs);
|
||||
int (*close)(lws_abs_transport_inst_t *d);
|
||||
int (*ask_for_writeable)(lws_abs_transport_inst_t *d);
|
||||
int (*set_timeout)(lws_abs_transport_inst_t *d, int reason, int secs);
|
||||
int (*state)(lws_abs_transport_inst_t *d);
|
||||
} lws_abs_transport_t;
|
||||
|
||||
/**
|
||||
* lws_abs_protocol_get_by_name() - returns a pointer to the named protocol ops
|
||||
*
|
||||
* \param name: the name of the abstract protocol
|
||||
*
|
||||
* Returns a pointer to the named protocol ops struct if available, otherwise
|
||||
* NULL.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN const lws_abs_transport_t *
|
||||
lws_abs_transport_get_by_name(const char *name);
|
||||
|
||||
/*
|
||||
* bring in public api pieces from transports
|
||||
*/
|
||||
|
||||
#include <libwebsockets/abstract/transports/raw-skt.h>
|
||||
#include <libwebsockets/abstract/transports/unit-test.h>
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
enum {
|
||||
LTMI_PEER_V_DNS_ADDRESS = LTMI_TRANSPORT_BASE, /* u.value */
|
||||
LTMI_PEER_LV_PORT, /* u.lvalue */
|
||||
LTMI_PEER_LV_TLS_FLAGS, /* u.lvalue */
|
||||
};
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*
|
||||
* This is an abstract transport useful for unit testing abstract protocols.
|
||||
*
|
||||
* Instead of passing data anywhere, you give the transport a list of packets
|
||||
* to deliver and packets you expect back from the abstract protocol it's
|
||||
* bound to.
|
||||
*/
|
||||
|
||||
enum {
|
||||
LWS_AUT_EXPECT_TEST_END = (1 << 0),
|
||||
LWS_AUT_EXPECT_LOCAL_CLOSE = (1 << 1),
|
||||
LWS_AUT_EXPECT_DO_REMOTE_CLOSE = (1 << 2),
|
||||
LWS_AUT_EXPECT_TX /* expect this as tx from protocol */ = (1 << 3),
|
||||
LWS_AUT_EXPECT_RX /* present this as rx to protocol */ = (1 << 4),
|
||||
LWS_AUT_EXPECT_SHOULD_FAIL = (1 << 5),
|
||||
LWS_AUT_EXPECT_SHOULD_TIMEOUT = (1 << 6),
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LPE_CONTINUE,
|
||||
LPE_SUCCEEDED,
|
||||
LPE_FAILED,
|
||||
LPE_FAILED_UNEXPECTED_TIMEOUT,
|
||||
LPE_FAILED_UNEXPECTED_PASS,
|
||||
LPE_FAILED_UNEXPECTED_CLOSE,
|
||||
LPE_SKIPPED,
|
||||
LPE_CLOSING
|
||||
} lws_unit_test_packet_disposition;
|
||||
|
||||
typedef int (*lws_unit_test_packet_test_cb)(const void *cb_user, int disposition);
|
||||
typedef int (*lws_unit_test_packet_cb)(lws_abs_t *instance);
|
||||
|
||||
/* each step in the unit test */
|
||||
|
||||
typedef struct lws_unit_test_packet {
|
||||
void *buffer;
|
||||
lws_unit_test_packet_cb pre;
|
||||
size_t len;
|
||||
|
||||
uint32_t flags;
|
||||
} lws_unit_test_packet_t;
|
||||
|
||||
/* each unit test */
|
||||
|
||||
typedef struct lws_unit_test {
|
||||
const char * name; /* NULL indicates end of test array */
|
||||
lws_unit_test_packet_t * expect_array;
|
||||
int max_secs;
|
||||
} lws_unit_test_t;
|
||||
|
||||
enum {
|
||||
LTMI_PEER_V_EXPECT_TEST = LTMI_TRANSPORT_BASE, /* u.value */
|
||||
LTMI_PEER_V_EXPECT_RESULT_CB, /* u.value */
|
||||
LTMI_PEER_V_EXPECT_RESULT_CB_ARG, /* u.value */
|
||||
};
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN const char *
|
||||
lws_unit_test_result_name(int in);
|
||||
|
|
@ -171,11 +171,6 @@ struct lws_client_connect_info {
|
|||
* tokens
|
||||
*/
|
||||
|
||||
struct lws_sequencer *seq;
|
||||
/**< NULL, or an lws_seq_t that wants to be given messages about
|
||||
* this wsi's lifecycle as it connects, errors or closes.
|
||||
*/
|
||||
|
||||
void *opaque_user_data;
|
||||
/**< This data has no meaning to lws but is applied to the client wsi
|
||||
* and can be retrieved by user code with lws_get_opaque_user_data().
|
||||
|
|
|
@ -201,7 +201,7 @@ struct lws_context_standalone;
|
|||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_sspc_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
||||
void *opaque_user_data, struct lws_sspc_handle **ppss,
|
||||
struct lws_sequencer *seq_owner, const char **ppayload_fmt);
|
||||
void *reserved, const char **ppayload_fmt);
|
||||
|
||||
/**
|
||||
* lws_sspc_destroy() - Destroy secure stream
|
||||
|
@ -256,19 +256,6 @@ lws_sspc_request_tx_len(struct lws_sspc_handle *h, unsigned long len);
|
|||
LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t
|
||||
lws_sspc_client_connect(struct lws_sspc_handle *h);
|
||||
|
||||
/**
|
||||
* lws_sspc_get_sequencer() - Return parent sequencer pointer if any
|
||||
*
|
||||
* \param h: secure streams handle
|
||||
*
|
||||
* Returns NULL if the secure stream is not associated with a sequencer.
|
||||
* Otherwise returns a pointer to the owning sequencer. You can use this to
|
||||
* identify which sequencer to direct messages to, from the secure stream
|
||||
* callback.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
|
||||
lws_sspc_get_sequencer(struct lws_sspc_handle *h);
|
||||
|
||||
/**
|
||||
* lws_sspc_proxy_create() - Start a unix domain socket proxy for Secure Streams
|
||||
*
|
||||
|
|
|
@ -309,7 +309,7 @@ typedef struct lws_ss_info {
|
|||
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
||||
void *opaque_user_data, struct lws_ss_handle **ppss,
|
||||
struct lws_sequencer *seq_owner, const char **ppayload_fmt);
|
||||
void *reserved, const char **ppayload_fmt);
|
||||
|
||||
/**
|
||||
* lws_ss_destroy() - Destroy secure stream
|
||||
|
@ -367,19 +367,6 @@ lws_ss_request_tx_len(struct lws_ss_handle *pss, unsigned long len);
|
|||
LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t LWS_WARN_UNUSED_RESULT
|
||||
lws_ss_client_connect(struct lws_ss_handle *h);
|
||||
|
||||
/**
|
||||
* lws_ss_get_sequencer() - Return parent sequencer pointer if any
|
||||
*
|
||||
* \param h: secure streams handle
|
||||
*
|
||||
* Returns NULL if the secure stream is not associated with a sequencer.
|
||||
* Otherwise returns a pointer to the owning sequencer. You can use this to
|
||||
* identify which sequencer to direct messages to, from the secure stream
|
||||
* callback.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
|
||||
lws_ss_get_sequencer(struct lws_ss_handle *h);
|
||||
|
||||
/**
|
||||
* lws_ss_proxy_create() - Start a unix domain socket proxy for Secure Streams
|
||||
*
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*
|
||||
* lws_sequencer is intended to help implement sequences that:
|
||||
*
|
||||
* - outlive a single connection lifetime,
|
||||
* - are not associated with a particular protocol,
|
||||
* - are not associated with a particular vhost,
|
||||
* - must receive and issue events inside the event loop
|
||||
*
|
||||
* lws_sequencer-s are bound to a pt (per-thread) which for the default case of
|
||||
* one service thread is the same as binding to an lws_context.
|
||||
*/
|
||||
/*
|
||||
* retry backoff table... retry n happens after .retry_ms_table[n] ms, with
|
||||
* the last entry used if n is greater than the number of entries.
|
||||
*
|
||||
* The first .conceal_count retries are concealed, but after that the failures
|
||||
* are reported.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
LWSSEQ_CREATED, /* sequencer created */
|
||||
LWSSEQ_DESTROYED, /* sequencer destroyed */
|
||||
LWSSEQ_TIMED_OUT, /* sequencer timeout */
|
||||
LWSSEQ_HEARTBEAT, /* 1Hz callback */
|
||||
|
||||
LWSSEQ_WSI_CONNECTED, /* wsi we bound to us has connected */
|
||||
LWSSEQ_WSI_CONN_FAIL, /* wsi we bound to us has failed to connect */
|
||||
LWSSEQ_WSI_CONN_CLOSE, /* wsi we bound to us has closed */
|
||||
|
||||
|
||||
LWSSEQ_SS_STATE_BASE, /* secure streams owned by a sequencer provide
|
||||
* automatic messages about state changes on
|
||||
* the sequencer, passing the oridinal in the
|
||||
* event argument field. The message index is
|
||||
* LWSSEQ_SS_STATE_BASE + the enum from
|
||||
* lws_ss_constate_t */
|
||||
|
||||
LWSSEQ_USER_BASE = 100 /* define your events from here */
|
||||
} lws_seq_events_t;
|
||||
|
||||
typedef enum lws_seq_cb_return {
|
||||
LWSSEQ_RET_CONTINUE,
|
||||
LWSSEQ_RET_DESTROY
|
||||
} lws_seq_cb_return_t;
|
||||
|
||||
/*
|
||||
* handler for this sequencer. Return 0 if OK else nonzero to destroy the
|
||||
* sequencer. LWSSEQ_DESTROYED will be called back to the handler so it can
|
||||
* close / destroy any private assets associated with the sequence.
|
||||
*
|
||||
* The callback may return either LWSSEQ_RET_CONTINUE for the sequencer to
|
||||
* resume or LWSSEQ_RET_DESTROY to indicate the sequence is finished.
|
||||
*
|
||||
* Event indexes consist of some generic ones but mainly user-defined ones
|
||||
* starting from LWSSEQ_USER_BASE.
|
||||
*/
|
||||
typedef lws_seq_cb_return_t (*lws_seq_event_cb)(struct lws_sequencer *seq,
|
||||
void *user, int event, void *data, void *aux);
|
||||
|
||||
typedef struct lws_seq_info {
|
||||
struct lws_context *context; /* lws_context for seq */
|
||||
int tsi; /* thread service idx */
|
||||
size_t user_size; /* size of user alloc */
|
||||
void **puser; /* place ptr to user */
|
||||
lws_seq_event_cb cb; /* seq callback */
|
||||
const char *name; /* seq name */
|
||||
const lws_retry_bo_t *retry; /* retry policy */
|
||||
uint8_t wakesuspend:1; /* important enough to
|
||||
* wake system */
|
||||
} lws_seq_info_t;
|
||||
|
||||
/**
|
||||
* lws_seq_create() - create and bind sequencer to a pt
|
||||
*
|
||||
* \param info: information about sequencer to create
|
||||
*
|
||||
* This binds an abstract sequencer to a per-thread (by default, the single
|
||||
* event loop of an lws_context). After the event loop starts, the sequencer
|
||||
* will receive an LWSSEQ_CREATED event on its callback from the event loop
|
||||
* context, where it can begin its sequence flow.
|
||||
*
|
||||
* Lws itself will only call the callback subsequently with LWSSEQ_DESTROYED
|
||||
* when the sequencer is being destroyed.
|
||||
*
|
||||
* pt locking is used to protect the related data structures.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
|
||||
lws_seq_create(lws_seq_info_t *info);
|
||||
|
||||
/**
|
||||
* lws_seq_destroy() - destroy the sequencer
|
||||
*
|
||||
* \param seq: pointer to the the opaque sequencer pointer returned by
|
||||
* lws_seq_create()
|
||||
*
|
||||
* This proceeds to destroy the sequencer, calling LWSSEQ_DESTROYED and then
|
||||
* freeing the sequencer object itself. The pointed-to seq pointer will be
|
||||
* set to NULL.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_seq_destroy(struct lws_sequencer **seq);
|
||||
|
||||
/**
|
||||
* lws_seq_queue_event() - queue an event on the given sequencer
|
||||
*
|
||||
* \param seq: the opaque sequencer pointer returned by lws_seq_create()
|
||||
* \param e: the event index to queue
|
||||
* \param data: associated opaque (to lws) data to provide the callback
|
||||
* \param aux: second opaque data to provide the callback
|
||||
*
|
||||
* This queues the event on a given sequencer. Queued events are delivered one
|
||||
* per sequencer each subsequent time around the event loop, so the cb is called
|
||||
* from the event loop thread context.
|
||||
*
|
||||
* Notice that because the events are delivered in order from the event loop,
|
||||
* the scope of objects pointed to by \p data or \p aux may exceed the lifetime
|
||||
* of the thing containing the pointed-to data. So it's usually better to pass
|
||||
* values here.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_seq_queue_event(struct lws_sequencer *seq, lws_seq_events_t e, void *data,
|
||||
void *aux);
|
||||
|
||||
/**
|
||||
* lws_seq_check_wsi() - check if wsi still extant
|
||||
*
|
||||
* \param seq: the sequencer interested in the wsi
|
||||
* \param wsi: the wsi we want to confirm hasn't closed yet
|
||||
*
|
||||
* Check if wsi still extant, by peeking in the message queue for a
|
||||
* LWSSEQ_WSI_CONN_CLOSE message about wsi. (Doesn't need to do the same for
|
||||
* CONN_FAIL since that will never have produced any messages prior to that).
|
||||
*
|
||||
* Use this to avoid trying to perform operations on wsi that have already
|
||||
* closed but we didn't get to that message yet.
|
||||
*
|
||||
* Returns 0 if not closed yet or 1 if it has closed but we didn't process the
|
||||
* close message yet.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_seq_check_wsi(struct lws_sequencer *seq, struct lws *wsi);
|
||||
|
||||
#define LWSSEQTO_NONE 0
|
||||
|
||||
/**
|
||||
* lws_seq_timeout_us() - set a timeout by which the sequence must have
|
||||
* completed by a different event or inform the
|
||||
* sequencer
|
||||
*
|
||||
* \param seq: The sequencer to set the timeout on
|
||||
* \param us: How many us in the future to fire the timeout
|
||||
* LWS_SET_TIMER_USEC_CANCEL = cancel any existing timeout
|
||||
*
|
||||
* This api allows the sequencer to ask to be informed if it has not completed
|
||||
* or disabled its timeout after secs seconds. Lws will send a LWSSEQ_TIMED_OUT
|
||||
* event to the sequencer if the timeout expires.
|
||||
*
|
||||
* Typically the sequencer sets the timeout when starting a step, then waits to
|
||||
* hear a queued event informing it the step completed or failed. The timeout
|
||||
* provides a way to deal with the case the step neither completed nor failed
|
||||
* within the timeout period.
|
||||
*
|
||||
* Lws wsi timeouts are not really suitable for this since they are focused on
|
||||
* short-term protocol timeout protection and may be set and reset many times
|
||||
* in one transaction. Wsi timeouts also enforce closure of the wsi when they
|
||||
* trigger, sequencer timeouts have no side effect except to queue the
|
||||
* LWSSEQ_TIMED_OUT message and leave it to the sequencer to decide how to
|
||||
* react appropriately.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_seq_timeout_us(struct lws_sequencer *seq, lws_usec_t us);
|
||||
|
||||
/**
|
||||
* lws_seq_from_user(): get the lws_seq_t pointer from the user ptr
|
||||
*
|
||||
* \param u: the sequencer user allocation returned by lws_seq_create() or
|
||||
* provided in the sequencer callback
|
||||
*
|
||||
* This gets the lws_seq_t * from the sequencer user allocation pointer.
|
||||
* Actually these are allocated at the same time in one step, with the user
|
||||
* allocation immediately after the lws_seq_t, so lws can compute where
|
||||
* the lws_seq_t is from having the user allocation pointer. Since the
|
||||
* size of the lws_seq_t is unknown to user code, this helper does it for
|
||||
* you.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
|
||||
lws_seq_from_user(void *u);
|
||||
|
||||
/**
|
||||
* lws_seq_us_since_creation(): elapsed seconds since sequencer created
|
||||
*
|
||||
* \param seq: pointer to the lws_seq_t
|
||||
*
|
||||
* Returns the number of us elapsed since the lws_seq_t was
|
||||
* created. This is useful to calculate sequencer timeouts for the current
|
||||
* step considering a global sequencer lifetime limit.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN lws_usec_t
|
||||
lws_seq_us_since_creation(struct lws_sequencer *seq);
|
||||
|
||||
/**
|
||||
* lws_seq_name(): get the name of this sequencer
|
||||
*
|
||||
* \param seq: pointer to the lws_seq_t
|
||||
*
|
||||
* Returns the name given when the sequencer was created. This is useful to
|
||||
* annotate logging when then are multiple sequencers in play.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN const char *
|
||||
lws_seq_name(struct lws_sequencer *seq);
|
||||
|
||||
/**
|
||||
* lws_seq_get_context(): get the lws_context sequencer was created on
|
||||
*
|
||||
* \param seq: pointer to the lws_seq_t
|
||||
*
|
||||
* Returns the lws_context. Saves you having to store it if you have a seq
|
||||
* pointer handy.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_context *
|
||||
lws_seq_get_context(struct lws_sequencer *seq);
|
|
@ -139,9 +139,6 @@ endif()
|
|||
|
||||
if (LWS_WITH_NETWORK)
|
||||
add_subdir_include_dirs(core-net)
|
||||
if (LWS_WITH_ABSTRACT)
|
||||
add_subdir_include_dirs(abstract)
|
||||
endif()
|
||||
add_subdir_include_dirs(roles)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2020 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.
|
||||
#
|
||||
# The strategy is to only export to PARENT_SCOPE
|
||||
#
|
||||
# - changes to LIB_LIST
|
||||
# - changes to SOURCES
|
||||
# - includes via include_directories
|
||||
#
|
||||
# and keep everything else private
|
||||
|
||||
include_directories(.)
|
||||
|
||||
list(APPEND SOURCES
|
||||
abstract/abstract.c
|
||||
)
|
||||
if (LWS_WITH_SEQUENCER)
|
||||
list(APPEND SOURCES
|
||||
abstract/test-sequencer.c)
|
||||
endif()
|
||||
|
||||
list(APPEND SOURCES
|
||||
abstract/transports/unit-test.c)
|
||||
|
||||
#if (LWS_WITH_SMTP)
|
||||
# list(APPEND SOURCES
|
||||
# abstract/protocols/smtp/smtp.c
|
||||
# abstract/protocols/smtp/smtp-sequencer.c
|
||||
# )
|
||||
#endif()
|
||||
|
||||
#
|
||||
# Keep explicit parent scope exports at end
|
||||
#
|
||||
|
||||
exports_to_parent_scope()
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
# Abstract protocols and transports
|
||||
|
||||
## Overview
|
||||
|
||||
Until now protocol implementations in lws have been done directly
|
||||
to the network-related apis inside lws.
|
||||
|
||||
In an effort to separate out completely network implementation
|
||||
details from protocol specification, lws now supports
|
||||
"abstract protocols" and "abstract transports".
|
||||
|
||||

|
||||
|
||||
The concept is that the implementation is split into two separate
|
||||
chunks of code hidden behind "ops" structs... the "abstract protocol"
|
||||
implementation is responsible for the logical protocol operation
|
||||
and reads and writes only memory buffers.
|
||||
|
||||
The "abstract transport" implementation is responsible for sending
|
||||
and receiving buffers on some kind of transport, and again is hidden
|
||||
behind a standardized ops struct.
|
||||
|
||||
In the system, both the abstract protocols and transports are
|
||||
found by their name.
|
||||
|
||||
An actual "connection" is created by calling a generic api
|
||||
`lws_abs_bind_and_create_instance()` to instantiate the
|
||||
combination of a protocol and a transport.
|
||||
|
||||
This makes it possible to confidently offer the same protocol on
|
||||
completely different transports, eg, like serial, or to wire
|
||||
up the protocol implementation to a test jig sending canned
|
||||
test vectors and confirming the response at buffer level, without
|
||||
any network. The abstract protocol itself has no relationship
|
||||
to the transport at all and is completely unchanged by changes
|
||||
to the transport.
|
||||
|
||||
In addition, generic tokens to control settings in both the
|
||||
protocol and the transport are passed in at instantiation-time,
|
||||
eg, controlling the IP address targeted by the transport.
|
||||
|
||||
lws SMTP client support has been rewritten to use the new scheme,
|
||||
and lws provides a raw socket transport built-in.
|
||||
|
||||
## Public API
|
||||
|
||||
The public api for defining abstract protocols and transports is
|
||||
found at
|
||||
|
||||
- [abstract.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/abstract/abstract.h)
|
||||
- [protocols.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/abstract/protocols.h)
|
||||
- [transports.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/abstract/transports.h)
|
||||
|
||||
### `lws_abs_t`
|
||||
|
||||
The main structure that defines the abstraction is `lws_abs_t`,
|
||||
this is a name and then pointers to the protocol and transport,
|
||||
optional tokens to control both the protocol and transport,
|
||||
and pointers to private allocations for both the
|
||||
protocol and transport when instantiated.
|
||||
|
||||
The transport is selected using
|
||||
|
||||
```
|
||||
LWS_VISIBLE LWS_EXTERN const lws_abs_transport_t *
|
||||
lws_abs_transport_get_by_name(const char *name);
|
||||
```
|
||||
|
||||
and similarly the protocol by
|
||||
|
||||
```
|
||||
LWS_VISIBLE LWS_EXTERN const lws_abs_protocol_t *
|
||||
lws_abs_protocol_get_by_name(const char *name);
|
||||
```
|
||||
|
||||
At the moment only "`raw-skt`" is defined as an lws built-in, athough
|
||||
you can also create your own mock transport the same way for creating
|
||||
test jigs.
|
||||
|
||||
|transport op|meaning|
|
||||
|---|---|
|
||||
|`tx()`|transmit a buffer|
|
||||
|`client_conn()`|start a connection to a peer|
|
||||
|`close()`|request to close the connection to a peer|
|
||||
|`ask_for_writeable()`|request a `writeable()` callback when tx can be used|
|
||||
|`set_timeout()`|set a timeout that will close the connection if reached|
|
||||
|`state()`|check if the connection is established and can carry traffic|
|
||||
|
||||
These are called by the protocol to get things done and make queries
|
||||
through the abstract transport.
|
||||
|
||||
|protocol op|meaning|
|
||||
|---|---|
|
||||
|`accept()`|The peer has accepted the transport connection|
|
||||
|`rx()`|The peer has sent us some payload|
|
||||
|`writeable()`|The connection to the peer can take more tx|
|
||||
|`closed()`|The connection to the peer has closed|
|
||||
|`heartbeat()`|Called periodically even when no network events|
|
||||
|
||||
These are called by the transport to inform the protocol of events
|
||||
and traffic.
|
||||
|
||||
### Instantiation
|
||||
|
||||
The user fills an lws_abs_t and passes a pointer to it to
|
||||
`lws_abs_bind_and_create_instance()` to create an instantiation
|
||||
of the protocol + transport.
|
||||
|
||||
### `lws_token_map_t`
|
||||
|
||||
The abstract protocol has no idea about a network or network addresses
|
||||
or ports or whatever... it may not even be hooked up to one.
|
||||
|
||||
If the transport it is bound to wants things like that, they are passed
|
||||
in using an array of `lws_token_map_t` at instantiation time.
|
||||
|
||||
For example this is passed to the raw socket protocol in the smtp client
|
||||
minimal example to control where it would connect to:
|
||||
|
||||
```
|
||||
static const lws_token_map_t smtp_abs_tokens[] = {
|
||||
{
|
||||
.u = { .value = "127.0.0.1" },
|
||||
.name_index = LTMI_PEER_DNS_ADDRESS,
|
||||
}, {
|
||||
.u = { .lvalue = 25l },
|
||||
.name_index = LTMI_PEER_PORT,
|
||||
}};
|
||||
```
|
||||
|
||||
## Steps for adding new abstract protocols
|
||||
|
||||
- add the public header in `./include/libwebsockets/abstract/protocols/`
|
||||
- add a directory under `./lib/abstract/protocols/`
|
||||
- add your protocol sources in the new directory
|
||||
- in CMakeLists.txt:
|
||||
- add an `LWS_WITH_xxx` for your protocol
|
||||
- search for "using any abstract protocol" and add your `LWS_WITH_xxx` to
|
||||
the if so it also sets `LWS_WITH_ABSTRACT` if any set
|
||||
- add a clause to append your source to SOURCES if `LWS_WITH_xxx` enabled
|
||||
- add your `lws_abs_protocol` to the list `available_abs_protocols` in
|
||||
`./lib/abstract/abstract.c`
|
||||
|
||||
## Steps for adding new abstract transports
|
||||
|
||||
- add the public header in `./include/libwebsockets/abstract/transports/`
|
||||
- add your transport sources under `./lib/abstract/transports/`
|
||||
- in CMakeLists.txt append your transport sources to SOURCES if `LWS_WITH_ABSTRACT`
|
||||
and any other cmake conditionals
|
||||
- add an extern for your transport `lws_protocols` in `./lib/core-net/private.h`
|
||||
- add your transport `lws_protocols` to `available_abstract_protocols` in
|
||||
`./lib/core-net/vhost.c`
|
||||
- add your `lws_abs_transport` to the list `available_abs_transports` in
|
||||
`./lib/abstract/abstract.c`
|
||||
|
||||
# Protocol testing
|
||||
|
||||
## unit tests
|
||||
|
||||
lws features an abstract transport designed to facilitate unit testing. This
|
||||
contains an lws_sequencer that performs the steps of tests involving sending the
|
||||
protocol test vector buffers and confirming the response of the protocol matches
|
||||
the test vectors.
|
||||
|
||||
## test-sequencer
|
||||
|
||||
test-sequencer is a helper that sequences running an array of unit tests and
|
||||
collects the statistics and gives a PASS / FAIL result.
|
||||
|
||||
See the SMTP client api test for an example of how to use.
|
|
@ -1,355 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include <private-lib-abstract.h>
|
||||
|
||||
extern const lws_abs_transport_t lws_abs_transport_cli_raw_skt,
|
||||
lws_abs_transport_cli_unit_test;
|
||||
#if defined(LWS_WITH_SMTP)
|
||||
extern const lws_abs_protocol_t lws_abs_protocol_smtp;
|
||||
#endif
|
||||
#if defined(LWS_WITH_MQTT)
|
||||
extern const lws_abs_protocol_t lws_abs_protocol_mqttc;
|
||||
#endif
|
||||
|
||||
static const lws_abs_transport_t * const available_abs_transports[] = {
|
||||
&lws_abs_transport_cli_raw_skt,
|
||||
&lws_abs_transport_cli_unit_test,
|
||||
};
|
||||
|
||||
#if defined(LWS_WITH_ABSTRACT)
|
||||
static const lws_abs_protocol_t * const available_abs_protocols[] = {
|
||||
#if defined(LWS_WITH_SMTP)
|
||||
&lws_abs_protocol_smtp,
|
||||
#endif
|
||||
#if defined(LWS_WITH_MQTT)
|
||||
&lws_abs_protocol_mqttc,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
const lws_abs_transport_t *
|
||||
lws_abs_transport_get_by_name(const char *name)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(available_abs_transports); n++)
|
||||
if (!strcmp(name, available_abs_transports[n]->name))
|
||||
return available_abs_transports[n];
|
||||
|
||||
lwsl_err("%s: cannot find '%s'\n", __func__, name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const lws_abs_protocol_t *
|
||||
lws_abs_protocol_get_by_name(const char *name)
|
||||
{
|
||||
#if defined(LWS_WITH_ABSTRACT)
|
||||
int n;
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(available_abs_protocols); n++)
|
||||
if (!strcmp(name, available_abs_protocols[n]->name))
|
||||
return available_abs_protocols[n];
|
||||
#endif
|
||||
lwsl_err("%s: cannot find '%s'\n", __func__, name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const lws_token_map_t *
|
||||
lws_abs_get_token(const lws_token_map_t *token_map, short name_index)
|
||||
{
|
||||
if (!token_map)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
if (token_map->name_index == name_index)
|
||||
return token_map;
|
||||
token_map++;
|
||||
} while (token_map->name_index);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_abstract_compare_connection(lws_abs_t *abs1, lws_abs_t *abs2)
|
||||
{
|
||||
/* it has to be using the same protocol */
|
||||
if (abs1->ap != abs2->ap)
|
||||
return 1;
|
||||
|
||||
/* protocol has to allow some kind of binding */
|
||||
if (!abs1->ap->flags)
|
||||
return 1;
|
||||
|
||||
/* it has to be using the same transport */
|
||||
if (abs1->at != abs2->at)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* The transport must feel the endpoint and conditions in use match the
|
||||
* requested endpoint and conditions... and the transport type must be
|
||||
* willing to allow it
|
||||
*/
|
||||
if (abs1->at->compare(abs1, abs2))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* The protocol must feel they are in compatible modes if any
|
||||
* (and the protocol type must be willing to allow it)
|
||||
*/
|
||||
if (abs1->ap->compare(abs1, abs2))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If no objection by now, we can say there's already a comparable
|
||||
* connection and both the protocol and transport feel we can make
|
||||
* use of it.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
find_compatible(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_abs_t *ai1 = (lws_abs_t *)user,
|
||||
*ai2 = lws_container_of(d, lws_abs_t, abstract_instances);
|
||||
|
||||
if (!lws_abstract_compare_connection(ai1, ai2)) {
|
||||
/* we can bind to it */
|
||||
lws_dll2_add_tail(&ai1->bound, &ai2->children_owner);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_abs_t *
|
||||
lws_abs_bind_and_create_instance(const lws_abs_t *abs)
|
||||
{
|
||||
size_t size = sizeof(lws_abs_t) + abs->ap->alloc + abs->at->alloc;
|
||||
lws_abs_t *ai;
|
||||
int n;
|
||||
|
||||
/*
|
||||
* since we know we will allocate the lws_abs_t, the protocol's
|
||||
* instance allocation, and the transport's instance allocation,
|
||||
* we merge it into a single heap allocation
|
||||
*/
|
||||
ai = lws_malloc(size, "abs inst");
|
||||
if (!ai)
|
||||
return NULL;
|
||||
|
||||
*ai = *abs;
|
||||
ai->ati = NULL;
|
||||
|
||||
ai->api = (char *)ai + sizeof(lws_abs_t);
|
||||
|
||||
if (!ai->ap->flags) /* protocol only understands single connections */
|
||||
goto fresh;
|
||||
|
||||
lws_vhost_lock(ai->vh); /* ----------------------------------- vh { */
|
||||
|
||||
/*
|
||||
* Let's have a look for any already-connected transport we can use
|
||||
*/
|
||||
|
||||
n = lws_dll2_foreach_safe(&ai->vh->abstract_instances_owner, ai,
|
||||
find_compatible);
|
||||
|
||||
lws_vhost_unlock(ai->vh); /* } vh --------------------------------- */
|
||||
|
||||
if (n)
|
||||
goto vh_list_add;
|
||||
|
||||
/* there's no existing connection doing what we want */
|
||||
|
||||
fresh:
|
||||
|
||||
ai->ati = (char *)ai->api + abs->ap->alloc;
|
||||
if (ai->at->create(ai)) {
|
||||
ai->ati = NULL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
vh_list_add:
|
||||
/* add us to the vhost's dll2 of instances */
|
||||
|
||||
lws_dll2_clear(&ai->abstract_instances);
|
||||
lws_dll2_add_head(&ai->abstract_instances,
|
||||
&ai->vh->abstract_instances_owner);
|
||||
|
||||
if (ai->ap->create(ai)) {
|
||||
ai->api = NULL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ai->bound.owner) { /* we are a piggybacker */
|
||||
lws_abs_t *ai2 = lws_container_of(ai->bound.owner, lws_abs_t,
|
||||
children_owner);
|
||||
/*
|
||||
* Provide an 'event' in the parent context to start handling
|
||||
* the bind if it's otherwise idle. We give the parent abs
|
||||
* because we don't know if we're "next" or whatever. Just that
|
||||
* a child joined him and he should look into his child
|
||||
* situation in case he was waiting for one to appear.
|
||||
*/
|
||||
if (ai2->ap->child_bind(ai2)) {
|
||||
lwsl_info("%s: anticpated child bind fail\n", __func__);
|
||||
lws_dll2_remove(&ai->bound);
|
||||
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
return ai;
|
||||
|
||||
bail:
|
||||
lws_abs_destroy_instance(&ai);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We get called to clean up each child that was still bound to a parent
|
||||
* at the time the parent is getting destroyed.
|
||||
*/
|
||||
|
||||
static void
|
||||
__lws_abs_destroy_instance2(lws_abs_t **ai)
|
||||
{
|
||||
lws_abs_t *a = *ai;
|
||||
|
||||
if (a->api)
|
||||
a->ap->destroy(&a->api);
|
||||
if (a->ati)
|
||||
a->at->destroy(&a->ati);
|
||||
|
||||
lws_dll2_remove(&a->abstract_instances);
|
||||
|
||||
*ai = NULL;
|
||||
free(a);
|
||||
}
|
||||
|
||||
static int
|
||||
__reap_children(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_abs_t *ac = lws_container_of(d, lws_abs_t, bound);
|
||||
|
||||
lws_dll2_foreach_safe(&ac->children_owner, NULL, __reap_children);
|
||||
|
||||
/* then destroy ourselves */
|
||||
|
||||
__lws_abs_destroy_instance2(&ac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_abs_destroy_instance(lws_abs_t **ai)
|
||||
{
|
||||
lws_abs_t *a = *ai;
|
||||
|
||||
/* destroy child instances that are bound to us first... */
|
||||
|
||||
lws_vhost_lock(a->vh); /* ----------------------------------- vh { */
|
||||
|
||||
lws_dll2_foreach_safe(&a->children_owner, NULL, __reap_children);
|
||||
|
||||
/* ...then destroy ourselves */
|
||||
|
||||
__lws_abs_destroy_instance2(ai);
|
||||
|
||||
lws_vhost_unlock(a->vh); /* } vh --------------------------------- */
|
||||
}
|
||||
|
||||
lws_abs_t *
|
||||
lws_abstract_alloc(struct lws_vhost *vhost, void *user,
|
||||
const char *abstract_path, const lws_token_map_t *ap_tokens,
|
||||
const lws_token_map_t *at_tokens, struct lws_sequencer *seq,
|
||||
void *opaque_user_data)
|
||||
{
|
||||
lws_abs_t *abs = lws_zalloc(sizeof(*abs), __func__);
|
||||
struct lws_tokenize ts;
|
||||
lws_tokenize_elem e;
|
||||
char tmp[30];
|
||||
|
||||
if (!abs)
|
||||
return NULL;
|
||||
|
||||
lws_tokenize_init(&ts, abstract_path, LWS_TOKENIZE_F_MINUS_NONTERM);
|
||||
|
||||
e = lws_tokenize(&ts);
|
||||
if (e != LWS_TOKZE_TOKEN)
|
||||
goto abs_path_problem;
|
||||
|
||||
if (lws_tokenize_cstr(&ts, tmp, sizeof(tmp)))
|
||||
goto abs_path_problem;
|
||||
|
||||
abs->ap = lws_abs_protocol_get_by_name(tmp);
|
||||
if (!abs->ap)
|
||||
goto abs_path_problem;
|
||||
|
||||
e = lws_tokenize(&ts);
|
||||
if (e != LWS_TOKZE_DELIMITER)
|
||||
goto abs_path_problem;
|
||||
|
||||
e = lws_tokenize(&ts);
|
||||
if (e != LWS_TOKZE_TOKEN)
|
||||
goto abs_path_problem;
|
||||
|
||||
if (lws_tokenize_cstr(&ts, tmp, sizeof(tmp)))
|
||||
goto abs_path_problem;
|
||||
|
||||
abs->at = lws_abs_transport_get_by_name(tmp);
|
||||
if (!abs->at)
|
||||
goto abs_path_problem;
|
||||
|
||||
abs->vh = vhost;
|
||||
abs->ap_tokens = ap_tokens;
|
||||
abs->at_tokens = at_tokens;
|
||||
abs->seq = seq;
|
||||
abs->opaque_user_data = opaque_user_data;
|
||||
|
||||
lwsl_info("%s: allocated %s\n", __func__, abstract_path);
|
||||
|
||||
return abs;
|
||||
|
||||
abs_path_problem:
|
||||
lwsl_err("%s: bad abs path '%s'\n", __func__, abstract_path);
|
||||
lws_free_set_NULL(abs);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lws_abstract_free(lws_abs_t **pabs)
|
||||
{
|
||||
if (*pabs)
|
||||
lws_free_set_NULL(*pabs);
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
#if !defined(__PRIVATE_LIB_ABSTRACT_H__)
|
||||
#define __PRIVATE_LIB_ABSTRACT_H__
|
||||
|
||||
typedef struct lws_token_map lws_token_map_t;
|
||||
typedef void lws_abs_transport_inst_t;
|
||||
typedef void lws_abs_protocol_inst_t;
|
||||
|
||||
typedef struct lws_abs {
|
||||
void *user;
|
||||
struct lws_vhost *vh;
|
||||
|
||||
const struct lws_abs_protocol *ap;
|
||||
const lws_token_map_t *ap_tokens;
|
||||
const struct lws_abs_transport *at;
|
||||
const lws_token_map_t *at_tokens;
|
||||
|
||||
struct lws_sequencer *seq;
|
||||
void *opaque_user_data;
|
||||
|
||||
/* vh lock */
|
||||
struct lws_dll2_owner children_owner; /* our children / queue */
|
||||
/* vh lock */
|
||||
struct lws_dll2 bound; /* parent or encapsulator */
|
||||
/* vh lock */
|
||||
struct lws_dll2 abstract_instances;
|
||||
lws_abs_transport_inst_t *ati;
|
||||
lws_abs_protocol_inst_t *api;
|
||||
} lws_abs_t;
|
||||
|
||||
#endif
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#define LWS_SMTP_MAX_EMAIL_LEN 32
|
||||
|
||||
|
||||
/*
|
||||
* These are allocated on to the heap with an over-allocation to hold the
|
||||
* payload at the end
|
||||
*/
|
||||
|
||||
typedef struct lws_smtp_email {
|
||||
struct lws_dll2 list;
|
||||
void *data;
|
||||
|
||||
char from[LWS_SMTP_MAX_EMAIL_LEN];
|
||||
char to[LWS_SMTP_MAX_EMAIL_LEN];
|
||||
|
||||
time_t added;
|
||||
time_t last_try;
|
||||
|
||||
lws_smtp_cb_t done;
|
||||
|
||||
int tries;
|
||||
|
||||
/* email payload follows */
|
||||
} lws_smtp_email_t;
|
|
@ -1,323 +0,0 @@
|
|||
/*
|
||||
* Abstract SMTP support for libwebsockets - SMTP sequencer
|
||||
*
|
||||
* Copyright (C) 2016-2019 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.
|
||||
*
|
||||
* This sequencer sits above the abstract protocol, and manages queueing,
|
||||
* retrying mail transmission, and retry limits.
|
||||
*
|
||||
* Having the sequencer means that, eg, we can manage retries after complete
|
||||
* connection failure.
|
||||
*
|
||||
* Connections to the smtp server are serialized
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-abstract-protocols-smtp.h"
|
||||
|
||||
typedef enum {
|
||||
LSMTPSS_DISCONNECTED,
|
||||
LSMTPSS_CONNECTING,
|
||||
LSMTPSS_CONNECTED,
|
||||
LSMTPSS_BUSY,
|
||||
} smtpss_connstate_t;
|
||||
|
||||
typedef struct lws_smtp_sequencer {
|
||||
struct lws_dll2_owner emails_owner; /* email queue */
|
||||
|
||||
lws_abs_t *abs, *instance;
|
||||
lws_smtp_sequencer_args_t args;
|
||||
struct lws_sequencer *seq;
|
||||
|
||||
smtpss_connstate_t connstate;
|
||||
|
||||
time_t email_connect_started;
|
||||
|
||||
/* holds the HELO for the smtp protocol to consume */
|
||||
lws_token_map_t apt[3];
|
||||
} lws_smtp_sequencer_t;
|
||||
|
||||
/* sequencer messages specific to this sequencer */
|
||||
|
||||
enum {
|
||||
SEQ_MSG_CLIENT_FAILED = LWSSEQ_USER_BASE,
|
||||
SEQ_MSG_CLIENT_DONE,
|
||||
};
|
||||
|
||||
/*
|
||||
* We're going to bind to the raw-skt transport, so tell that what we want it
|
||||
* to connect to
|
||||
*/
|
||||
|
||||
static const lws_token_map_t smtp_rs_transport_tokens[] = {
|
||||
{
|
||||
.u = { .value = "127.0.0.1" },
|
||||
.name_index = LTMI_PEER_V_DNS_ADDRESS,
|
||||
}, {
|
||||
.u = { .lvalue = 25 },
|
||||
.name_index = LTMI_PEER_LV_PORT,
|
||||
}, {
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
lws_smtpc_kick_internal(lws_smtp_sequencer_t *s)
|
||||
{
|
||||
lws_smtp_email_t *e;
|
||||
lws_dll2_t *d;
|
||||
char buf[64];
|
||||
int n;
|
||||
lws_dll2_t *pd2;
|
||||
|
||||
pd2 = lws_dll2_get_head(&s->emails_owner);
|
||||
if (!pd2)
|
||||
return;
|
||||
|
||||
e = lws_container_of(pd2, lws_smtp_email_t, list);
|
||||
if (!e)
|
||||
return;
|
||||
|
||||
/* Is there something to do? If so, we need a connection... */
|
||||
|
||||
if (s->connstate == LSMTPSS_DISCONNECTED) {
|
||||
|
||||
s->apt[0].u.value = s->args.helo;
|
||||
s->apt[0].name_index = LTMI_PSMTP_V_HELO;
|
||||
s->apt[1].u.value = (void *)e;
|
||||
s->apt[1].name_index = LTMI_PSMTP_V_LWS_SMTP_EMAIL_T;
|
||||
|
||||
/*
|
||||
* create and connect the smtp protocol + transport
|
||||
*/
|
||||
|
||||
s->abs = lws_abstract_alloc(s->args.vhost, NULL, "smtp.raw_skt",
|
||||
s->apt, smtp_rs_transport_tokens,
|
||||
s->seq, NULL);
|
||||
if (!s->abs)
|
||||
return;
|
||||
|
||||
s->instance = lws_abs_bind_and_create_instance(s->abs);
|
||||
if (!s->instance) {
|
||||
lws_abstract_free(&s->abs);
|
||||
lwsl_err("%s: failed to create SMTP client\n", __func__);
|
||||
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
s->connstate = LSMTPSS_CONNECTING;
|
||||
lws_seq_timeout_us(s->seq, 10 * LWS_USEC_PER_SEC);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ask the transport if we have a connection to the server ongoing */
|
||||
|
||||
if (s->abs->at->state(s->abs->ati)) {
|
||||
/*
|
||||
* there's a connection, it could be still trying to connect
|
||||
* or established
|
||||
*/
|
||||
s->abs->at->ask_for_writeable(s->abs->ati);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* there's no existing connection */
|
||||
|
||||
lws_smtpc_state_transition(c, LGSSMTP_CONNECTING);
|
||||
|
||||
if (s->abs->at->client_conn(s->abs)) {
|
||||
lwsl_err("%s: failed to connect\n", __func__);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
e->tries++;
|
||||
e->last_try = lws_now_secs();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The callback we get from the smtp protocol... we use this to drive
|
||||
* decisions about destroy email, retry and fail.
|
||||
*
|
||||
* Sequencer will handle it via the event loop.
|
||||
*/
|
||||
|
||||
static int
|
||||
email_result(void *e, void *d, int disp, void *b, size_t l)
|
||||
{
|
||||
lws_smtp_sequencer_t *s = (lws_smtp_sequencer_t *)d;
|
||||
|
||||
lws_sequencer_event(s->seq, LWSSEQ_USER_BASE + disp, e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cleanup(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_smtp_email_t *e;
|
||||
|
||||
e = lws_container_of(d, lws_smtp_email_t, list);
|
||||
if (e->done)
|
||||
e->done(e, "destroying", 10);
|
||||
|
||||
lws_dll2_remove(d);
|
||||
lws_free(e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lws_seq_cb_return_t
|
||||
smtp_sequencer_cb(struct lws_sequencer *seq, void *user, int event, void *data)
|
||||
{
|
||||
struct lws_smtp_sequencer_t *s = (struct lws_smtp_sequencer_t *)user;
|
||||
|
||||
switch ((int)event) {
|
||||
case LWSSEQ_CREATED: /* our sequencer just got started */
|
||||
lwsl_notice("%s: %s: created\n", __func__,
|
||||
lws_sequencer_name(seq));
|
||||
s->connstate = LSMTPSS_DISCONNECTED;
|
||||
s->state = 0; /* first thing we'll do is the first url */
|
||||
goto step;
|
||||
|
||||
case LWSSEQ_DESTROYED:
|
||||
lws_dll2_foreach_safe(&s->pending_owner, NULL, cleanup);
|
||||
break;
|
||||
|
||||
case LWSSEQ_TIMED_OUT:
|
||||
lwsl_notice("%s: LWSSEQ_TIMED_OUT\n", __func__);
|
||||
break;
|
||||
|
||||
case LWSSEQ_USER_BASE + LWS_SMTP_DISPOSITION_SENT:
|
||||
lws_smtpc_free_email(data);
|
||||
break;
|
||||
|
||||
case LWSSEQ_WSI_CONNECTED:
|
||||
s->connstate = LSMTPSS_CONNECTED;
|
||||
lws_smtpc_kick_internal(s);
|
||||
break;
|
||||
|
||||
case LWSSEQ_WSI_CONN_FAIL:
|
||||
case LWSSEQ_WSI_CONN_CLOSE:
|
||||
s->connstate = LSMTPSS_DISCONNECTED;
|
||||
lws_smtpc_kick_internal(s);
|
||||
break;
|
||||
|
||||
case SEQ_MSG_SENT:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return LWSSEQ_RET_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates an lws_sequencer to manage the test sequence
|
||||
*/
|
||||
|
||||
lws_smtp_sequencer_t *
|
||||
lws_smtp_sequencer_create(const lws_smtp_sequencer_args_t *args)
|
||||
{
|
||||
lws_smtp_sequencer_t *s;
|
||||
struct lws_sequencer *seq;
|
||||
|
||||
/*
|
||||
* Create a sequencer in the event loop to manage the SMTP queue
|
||||
*/
|
||||
|
||||
seq = lws_sequencer_create(args->vhost->context, 0,
|
||||
sizeof(lws_smtp_sequencer_t), (void **)&s,
|
||||
smtp_sequencer_cb, "smtp-seq");
|
||||
if (!seq) {
|
||||
lwsl_err("%s: unable to create sequencer\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->abs = *args->abs;
|
||||
s->args = *args;
|
||||
s->seq = seq;
|
||||
|
||||
/* set defaults in our copy of the args */
|
||||
|
||||
if (!s->args.helo[0])
|
||||
strcpy(s->args.helo, "default-helo");
|
||||
if (!s->args.email_queue_max)
|
||||
s->args.email_queue_max = 8;
|
||||
if (!s->args.retry_interval)
|
||||
s->args.retry_interval = 15 * 60;
|
||||
if (!s->args.delivery_timeout)
|
||||
s->args.delivery_timeout = 12 * 60 * 60;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
lws_smtp_sequencer_destroy(lws_smtp_sequencer_t *s)
|
||||
{
|
||||
/* sequencer destruction destroys all assets */
|
||||
lws_sequencer_destroy(&s->seq);
|
||||
}
|
||||
|
||||
int
|
||||
lws_smtpc_add_email(lws_smtp_sequencer_t *s, const char *payload,
|
||||
size_t payload_len, const char *sender,
|
||||
const char *recipient, void *data, lws_smtp_cb_t done)
|
||||
{
|
||||
lws_smtp_email_t *e;
|
||||
|
||||
if (s->emails_owner.count > s->args.email_queue_max) {
|
||||
lwsl_err("%s: email queue at limit of %d\n", __func__,
|
||||
(int)s->args.email_queue_max);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!done)
|
||||
return 1;
|
||||
|
||||
e = malloc(sizeof(*e) + payload_len + 1);
|
||||
if (!e)
|
||||
return 1;
|
||||
|
||||
memset(e, 0, sizeof(*e));
|
||||
|
||||
e->data = data;
|
||||
e->done = done;
|
||||
|
||||
lws_strncpy(e->from, sender, sizeof(e->from));
|
||||
lws_strncpy(e->to, recipient, sizeof(e->to));
|
||||
|
||||
memcpy((char *)&e[1], payload, payload_len + 1);
|
||||
|
||||
e->added = lws_now_secs();
|
||||
e->last_try = 0;
|
||||
e->tries = 0;
|
||||
|
||||
lws_dll2_clear(&e->list);
|
||||
lws_dll2_add_tail(&e->list, &s->emails_owner);
|
||||
|
||||
lws_smtpc_kick_internal(s);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,382 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-abstract.h"
|
||||
|
||||
/** enum lwsgs_smtp_states - where we are in SMTP protocol sequence */
|
||||
typedef enum lwsgs_smtp_states {
|
||||
LGSSMTP_IDLE, /**< awaiting new email */
|
||||
LGSSMTP_CONNECTING, /**< opening tcp connection to MTA */
|
||||
LGSSMTP_CONNECTED, /**< tcp connection to MTA is connected */
|
||||
/* (server sends greeting) */
|
||||
LGSSMTP_SENT_HELO, /**< sent the HELO */
|
||||
|
||||
LGSSMTP_SENT_FROM, /**< sent FROM */
|
||||
LGSSMTP_SENT_TO, /**< sent TO */
|
||||
LGSSMTP_SENT_DATA, /**< sent DATA request */
|
||||
LGSSMTP_SENT_BODY, /**< sent the email body */
|
||||
|
||||
/*
|
||||
* (server sends, eg, "250 Ok: queued as 12345")
|
||||
* at this point we can return to LGSSMTP_SENT_HELO and send a
|
||||
* new email, or continue below to QUIT, or just wait
|
||||
*/
|
||||
|
||||
LGSSMTP_SENT_QUIT, /**< sent the session quit */
|
||||
|
||||
/* (server sends, eg, "221 Bye" and closes the connection) */
|
||||
} lwsgs_smtp_states_t;
|
||||
|
||||
/** abstract protocol instance data */
|
||||
|
||||
typedef struct lws_smtp_client_protocol {
|
||||
const struct lws_abs *abs;
|
||||
lwsgs_smtp_states_t estate;
|
||||
|
||||
lws_smtp_email_t *e; /* the email we are trying to send */
|
||||
const char *helo;
|
||||
|
||||
unsigned char send_pending:1;
|
||||
} lws_smtpcp_t;
|
||||
|
||||
static const short retcodes[] = {
|
||||
0, /* idle */
|
||||
0, /* connecting */
|
||||
220, /* connected */
|
||||
250, /* helo */
|
||||
250, /* from */
|
||||
250, /* to */
|
||||
354, /* data */
|
||||
250, /* body */
|
||||
221, /* quit */
|
||||
};
|
||||
|
||||
static void
|
||||
lws_smtpc_state_transition(lws_smtpcp_t *c, lwsgs_smtp_states_t s)
|
||||
{
|
||||
lwsl_debug("%s: cli %p: state %d -> %d\n", __func__, c, c->estate, s);
|
||||
c->estate = s;
|
||||
}
|
||||
|
||||
static lws_smtp_email_t *
|
||||
lws_smtpc_get_email(lws_smtpcp_t *c)
|
||||
{
|
||||
const lws_token_map_t *tm;
|
||||
|
||||
/* ... the email we want to send */
|
||||
tm = lws_abs_get_token(c->abs->ap_tokens, LTMI_PSMTP_V_LWS_SMTP_EMAIL_T);
|
||||
if (!tm) {
|
||||
assert(0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (lws_smtp_email_t *)tm->u.value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when something happened so that we know now the final disposition of
|
||||
* the email send attempt, for good or ill.
|
||||
*
|
||||
* Inform the owner via the done callback and set up the next queued one if any.
|
||||
*
|
||||
* Returns nonzero if we queued a new one
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_smtpc_email_disposition(lws_smtpcp_t *c, int disp, const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
lws_smtpcp_t *ch;
|
||||
lws_abs_t *ach;
|
||||
lws_dll2_t *d;
|
||||
|
||||
lws_smtpc_state_transition(c, LGSSMTP_SENT_HELO);
|
||||
|
||||
/* lifetime of the email object is handled by done callback */
|
||||
c->e->done(c->e, c->e->data, disp, buf, len);
|
||||
c->e = NULL;
|
||||
|
||||
/* this may not be the time to try to send anything else... */
|
||||
|
||||
if (disp == LWS_SMTP_DISPOSITION_FAILED_DESTROY)
|
||||
return 0;
|
||||
|
||||
/* ... otherwise... do we have another queued? */
|
||||
|
||||
d = lws_dll2_get_tail(&c->abs->children_owner);
|
||||
if (!d)
|
||||
return 0;
|
||||
|
||||
ach = lws_container_of(d, lws_abs_t, bound);
|
||||
ch = (lws_smtpcp_t *)ach->api;
|
||||
|
||||
c->e = lws_smtpc_get_email(ch);
|
||||
|
||||
/* since we took it on, remove it from the queue */
|
||||
lws_dll2_remove(d);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* we became connected
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_smtpc_abs_accept(lws_abs_protocol_inst_t *api)
|
||||
{
|
||||
lws_smtpcp_t *c = (lws_smtpcp_t *)api;
|
||||
|
||||
/* we have become connected in the tcp sense */
|
||||
|
||||
lws_smtpc_state_transition(c, LGSSMTP_CONNECTED);
|
||||
|
||||
/*
|
||||
* From the accept(), the next thing that should happen is the SMTP
|
||||
* server sends its greeting like "220 smtp2.example.com ESMTP Postfix",
|
||||
* we'll hear about it in the rx callback, or time out
|
||||
*/
|
||||
|
||||
c->abs->at->set_timeout(c->abs->ati,
|
||||
PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtpc_abs_rx(lws_abs_protocol_inst_t *api, const uint8_t *buf, size_t len)
|
||||
{
|
||||
lws_smtpcp_t *c = (lws_smtpcp_t *)api;
|
||||
char dotstar[96], at[5];
|
||||
int n;
|
||||
|
||||
c->abs->at->set_timeout(c->abs->ati, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
lws_strncpy(at, (const char *)buf, sizeof(at));
|
||||
n = atoi(at);
|
||||
|
||||
switch (c->estate) {
|
||||
case LGSSMTP_CONNECTED:
|
||||
if (n != 220) {
|
||||
/*
|
||||
* The server did not properly greet us... we can't
|
||||
* even get started, so fail the transport connection
|
||||
* (and anything queued on it)
|
||||
*/
|
||||
|
||||
lws_strnncpy(dotstar, (const char *)buf, len, sizeof(dotstar));
|
||||
lwsl_err("%s: server: %s\n", __func__, dotstar);
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LGSSMTP_SENT_BODY:
|
||||
/*
|
||||
* We finished one way or another... let's prepare to send a
|
||||
* new one... or wait until server hangs up on us
|
||||
*/
|
||||
if (!lws_smtpc_email_disposition(c,
|
||||
n == 250 ? LWS_SMTP_DISPOSITION_SENT :
|
||||
LWS_SMTP_DISPOSITION_FAILED,
|
||||
"destroyed", 0))
|
||||
return 0; /* become idle */
|
||||
|
||||
break; /* ask to send */
|
||||
|
||||
case LGSSMTP_SENT_QUIT:
|
||||
lwsl_debug("%s: done\n", __func__);
|
||||
lws_smtpc_state_transition(c, LGSSMTP_IDLE);
|
||||
|
||||
return 1;
|
||||
|
||||
default:
|
||||
if (n != retcodes[c->estate]) {
|
||||
lws_strnncpy(dotstar, buf, len, sizeof(dotstar));
|
||||
lwsl_notice("%s: bad response: %d (state %d) %s\n",
|
||||
__func__, n, c->estate, dotstar);
|
||||
|
||||
lws_smtpc_email_disposition(c,
|
||||
LWS_SMTP_DISPOSITION_FAILED, buf, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
c->send_pending = 1;
|
||||
c->abs->at->ask_for_writeable(c->abs->ati);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtpc_abs_writeable(lws_abs_protocol_inst_t *api, size_t budget)
|
||||
{
|
||||
char b[256 + LWS_PRE], *p = b + LWS_PRE;
|
||||
lws_smtpcp_t *c = (lws_smtpcp_t *)api;
|
||||
int n;
|
||||
|
||||
if (!c->send_pending || !c->e)
|
||||
return 0;
|
||||
|
||||
c->send_pending = 0;
|
||||
|
||||
lwsl_debug("%s: writing response for state %d\n", __func__, c->estate);
|
||||
|
||||
switch (c->estate) {
|
||||
case LGSSMTP_CONNECTED:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE, "HELO %s\n", c->helo);
|
||||
lws_smtpc_state_transition(c, LGSSMTP_SENT_HELO);
|
||||
break;
|
||||
|
||||
case LGSSMTP_SENT_HELO:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE, "MAIL FROM: <%s>\n",
|
||||
c->e->from);
|
||||
lws_smtpc_state_transition(c, LGSSMTP_SENT_FROM);
|
||||
break;
|
||||
|
||||
case LGSSMTP_SENT_FROM:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE,
|
||||
"RCPT TO: <%s>\n", c->e->to);
|
||||
lws_smtpc_state_transition(c, LGSSMTP_SENT_TO);
|
||||
break;
|
||||
|
||||
case LGSSMTP_SENT_TO:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE, "DATA\n");
|
||||
lws_smtpc_state_transition(c, LGSSMTP_SENT_DATA);
|
||||
break;
|
||||
|
||||
case LGSSMTP_SENT_DATA:
|
||||
p = (char *)&c->e[1];
|
||||
n = strlen(p);
|
||||
lws_smtpc_state_transition(c, LGSSMTP_SENT_BODY);
|
||||
break;
|
||||
|
||||
case LGSSMTP_SENT_BODY:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE, "quit\n");
|
||||
lws_smtpc_state_transition(c, LGSSMTP_SENT_QUIT);
|
||||
break;
|
||||
|
||||
case LGSSMTP_SENT_QUIT:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
//puts(p);
|
||||
c->abs->at->tx(c->abs->ati, (uint8_t *)p, n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtpc_abs_closed(lws_abs_protocol_inst_t *api)
|
||||
{
|
||||
lws_smtpcp_t *c = (lws_smtpcp_t *)api;
|
||||
|
||||
if (c)
|
||||
lws_smtpc_state_transition(c, LGSSMTP_IDLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creating for initial transport and for piggybacking on another transport
|
||||
* both get created here the same. But piggybackers have ai->bound attached.
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_smtpc_create(const lws_abs_t *ai)
|
||||
{
|
||||
lws_smtpcp_t *c = (lws_smtpcp_t *)ai->api;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
|
||||
c->abs = ai;
|
||||
c->e = lws_smtpc_get_email(c);
|
||||
|
||||
lws_smtpc_state_transition(c, lws_dll2_is_detached(&ai->bound) ?
|
||||
LGSSMTP_CONNECTING : LGSSMTP_IDLE);
|
||||
|
||||
/* If we are initiating the transport, we will get an accept() next...
|
||||
*
|
||||
* If we are piggybacking, the parent will get a .child_bind() after
|
||||
* this to give it a chance to act on us joining (eg, it was completely
|
||||
* idle and we joined).
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_smtpc_destroy(lws_abs_protocol_inst_t **_c)
|
||||
{
|
||||
lws_smtpcp_t *c = (lws_smtpcp_t *)*_c;
|
||||
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
/* so if we are still holding on to c->e, we have failed to send it */
|
||||
if (c->e)
|
||||
lws_smtpc_email_disposition(c,
|
||||
LWS_SMTP_DISPOSITION_FAILED_DESTROY, "destroyed", 0);
|
||||
|
||||
*_c = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtpc_compare(lws_abs_t *abs1, lws_abs_t *abs2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtpc_child_bind(lws_abs_t *abs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* events the transport invokes (handled by abstract protocol) */
|
||||
|
||||
const lws_abs_protocol_t lws_abs_protocol_smtp = {
|
||||
.name = "smtp",
|
||||
.alloc = sizeof(lws_smtpcp_t),
|
||||
.flags = LWSABSPR_FLAG_PIPELINE,
|
||||
|
||||
.create = lws_smtpc_create,
|
||||
.destroy = lws_smtpc_destroy,
|
||||
.compare = lws_smtpc_compare,
|
||||
|
||||
.accept = lws_smtpc_abs_accept,
|
||||
.rx = lws_smtpc_abs_rx,
|
||||
.writeable = lws_smtpc_abs_writeable,
|
||||
.closed = lws_smtpc_abs_closed,
|
||||
.heartbeat = NULL,
|
||||
|
||||
.child_bind = lws_smtpc_child_bind,
|
||||
};
|
|
@ -1,274 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*
|
||||
* A helper for running multiple unit tests against abstract protocols.
|
||||
*
|
||||
* An lws_seq_t is used to base its actions in the event loop and manage
|
||||
* the sequencing of multiple tests. A new abstract connection is instantiated
|
||||
* for each test using te
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
|
||||
struct lws_seq_test_sequencer {
|
||||
lws_abs_t original_abs;
|
||||
|
||||
lws_test_sequencer_args_t args;
|
||||
|
||||
struct lws_context *context;
|
||||
struct lws_vhost *vhost;
|
||||
struct lws_sequencer *unit_test_seq;
|
||||
|
||||
/* holds the per-test token for the unit-test transport to consume */
|
||||
lws_token_map_t uttt[4];
|
||||
|
||||
lws_abs_t *instance;
|
||||
|
||||
int state;
|
||||
};
|
||||
|
||||
/* sequencer messages specific to this sequencer */
|
||||
|
||||
enum {
|
||||
SEQ_MSG_PASS = LWSSEQ_USER_BASE,
|
||||
SEQ_MSG_FAIL,
|
||||
SEQ_MSG_FAIL_TIMEOUT,
|
||||
};
|
||||
|
||||
/*
|
||||
* We get called back when the unit test transport has decided if the test
|
||||
* passed or failed. We get the priv, and report to the sequencer message queue
|
||||
* what the result was.
|
||||
*/
|
||||
|
||||
static int
|
||||
unit_test_result_cb(const void *cb_user, int disposition)
|
||||
{
|
||||
const struct lws_seq_test_sequencer *s =
|
||||
(const struct lws_seq_test_sequencer *)cb_user;
|
||||
int r;
|
||||
|
||||
lwsl_debug("%s: disp %d\n", __func__, disposition);
|
||||
|
||||
switch (disposition) {
|
||||
case LPE_FAILED_UNEXPECTED_PASS:
|
||||
case LPE_FAILED_UNEXPECTED_CLOSE:
|
||||
case LPE_FAILED:
|
||||
r = SEQ_MSG_FAIL;
|
||||
break;
|
||||
|
||||
case LPE_FAILED_UNEXPECTED_TIMEOUT:
|
||||
r = SEQ_MSG_FAIL_TIMEOUT;
|
||||
break;
|
||||
|
||||
case LPE_SUCCEEDED:
|
||||
r = SEQ_MSG_PASS;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lws_seq_queue_event(s->unit_test_seq, r, NULL, NULL);
|
||||
|
||||
((struct lws_seq_test_sequencer *)s)->instance = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We receive the unit test result callback's messages via the message queue.
|
||||
*
|
||||
* We log the results and always move on to the next test until there are no
|
||||
* more tests.
|
||||
*/
|
||||
|
||||
static lws_seq_cb_return_t
|
||||
test_sequencer_cb(struct lws_sequencer *seq, void *user, int event, void *data,
|
||||
void *aux)
|
||||
{
|
||||
struct lws_seq_test_sequencer *s =
|
||||
(struct lws_seq_test_sequencer *)user;
|
||||
lws_unit_test_packet_t *exp = (lws_unit_test_packet_t *)
|
||||
s->args.tests[s->state].expect_array;
|
||||
lws_abs_t test_abs;
|
||||
|
||||
switch ((int)event) {
|
||||
case LWSSEQ_CREATED: /* our sequencer just got started */
|
||||
lwsl_notice("%s: %s: created\n", __func__,
|
||||
lws_seq_name(seq));
|
||||
s->state = 0; /* first thing we'll do is the first url */
|
||||
goto step;
|
||||
|
||||
case LWSSEQ_DESTROYED:
|
||||
/*
|
||||
* We are going down... if we have a child unit test sequencer
|
||||
* still around inform and destroy it
|
||||
*/
|
||||
if (s->instance) {
|
||||
s->instance->at->close(s->instance);
|
||||
s->instance = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEQ_MSG_FAIL_TIMEOUT: /* current step timed out */
|
||||
if (exp->flags & LWS_AUT_EXPECT_SHOULD_TIMEOUT) {
|
||||
lwsl_user("%s: test %d got expected timeout\n",
|
||||
__func__, s->state);
|
||||
|
||||
goto pass;
|
||||
}
|
||||
lwsl_user("%s: seq timed out at step %d\n", __func__, s->state);
|
||||
|
||||
s->args.results[s->state] = LPE_FAILED_UNEXPECTED_TIMEOUT;
|
||||
goto done; /* always move on to the next test */
|
||||
|
||||
case SEQ_MSG_FAIL:
|
||||
if (exp->flags & LWS_AUT_EXPECT_SHOULD_FAIL) {
|
||||
/*
|
||||
* in this case, we expected to fail like this, it's OK
|
||||
*/
|
||||
lwsl_user("%s: test %d failed as expected\n",
|
||||
__func__, s->state);
|
||||
|
||||
goto pass; /* always move on to the next test */
|
||||
}
|
||||
|
||||
lwsl_user("%s: seq failed at step %d\n", __func__, s->state);
|
||||
|
||||
s->args.results[s->state] = LPE_FAILED;
|
||||
goto done; /* always move on to the next test */
|
||||
|
||||
case SEQ_MSG_PASS:
|
||||
if (exp->flags & (LWS_AUT_EXPECT_SHOULD_FAIL |
|
||||
LWS_AUT_EXPECT_SHOULD_TIMEOUT)) {
|
||||
/*
|
||||
* In these specific cases, done would be a failure,
|
||||
* we expected to timeout or fail
|
||||
*/
|
||||
lwsl_user("%s: seq failed at step %d\n", __func__,
|
||||
s->state);
|
||||
|
||||
s->args.results[s->state] = LPE_FAILED_UNEXPECTED_PASS;
|
||||
|
||||
goto done; /* always move on to the next test */
|
||||
}
|
||||
lwsl_info("%s: seq done test %d\n", __func__, s->state);
|
||||
pass:
|
||||
(*s->args.count_passes)++;
|
||||
s->args.results[s->state] = LPE_SUCCEEDED;
|
||||
|
||||
done:
|
||||
lws_seq_timeout_us(lws_seq_from_user(s), LWSSEQTO_NONE);
|
||||
s->state++;
|
||||
step:
|
||||
if (!s->args.tests[s->state].name) {
|
||||
/* the sequence has completed */
|
||||
lwsl_user("%s: sequence completed OK\n", __func__);
|
||||
|
||||
if (s->args.cb)
|
||||
s->args.cb(s->args.cb_user);
|
||||
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
}
|
||||
lwsl_info("%s: starting test %d\n", __func__, s->state);
|
||||
|
||||
if (s->state >= s->args.results_max) {
|
||||
lwsl_err("%s: results array is too small\n", __func__);
|
||||
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
}
|
||||
test_abs = s->original_abs;
|
||||
s->uttt[0].name_index = LTMI_PEER_V_EXPECT_TEST;
|
||||
s->uttt[0].u.value = (void *)&s->args.tests[s->state];
|
||||
s->uttt[1].name_index = LTMI_PEER_V_EXPECT_RESULT_CB;
|
||||
s->uttt[1].u.value = (void *)unit_test_result_cb;
|
||||
s->uttt[2].name_index = LTMI_PEER_V_EXPECT_RESULT_CB_ARG;
|
||||
s->uttt[2].u.value = (void *)s;
|
||||
/* give the unit test transport the test tokens */
|
||||
test_abs.at_tokens = s->uttt;
|
||||
|
||||
s->instance = lws_abs_bind_and_create_instance(&test_abs);
|
||||
if (!s->instance) {
|
||||
lwsl_notice("%s: failed to create step %d unit test\n",
|
||||
__func__, s->state);
|
||||
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
}
|
||||
(*s->args.count_tests)++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return LWSSEQ_RET_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Creates an lws_sequencer to manage the test sequence
|
||||
*/
|
||||
|
||||
int
|
||||
lws_abs_unit_test_sequencer(const lws_test_sequencer_args_t *args)
|
||||
{
|
||||
struct lws_seq_test_sequencer *s;
|
||||
struct lws_sequencer *seq;
|
||||
lws_seq_info_t i;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.context = args->abs->vh->context;
|
||||
i.user_size = sizeof(struct lws_seq_test_sequencer);
|
||||
i.puser = (void **)&s;
|
||||
i.cb = test_sequencer_cb;
|
||||
i.name = "test-seq";
|
||||
|
||||
/*
|
||||
* Create a sequencer in the event loop to manage the tests
|
||||
*/
|
||||
|
||||
seq = lws_seq_create(&i);
|
||||
if (!seq) {
|
||||
lwsl_err("%s: unable to create sequencer\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a copy of the original lws_abs_t we were passed so we can use
|
||||
* it as the basis of the lws_abs_t we create the individual tests with
|
||||
*/
|
||||
s->original_abs = *args->abs;
|
||||
|
||||
s->args = *args;
|
||||
|
||||
s->context = args->abs->vh->context;
|
||||
s->vhost = args->abs->vh;
|
||||
s->unit_test_seq = seq;
|
||||
|
||||
*s->args.count_tests = 0;
|
||||
*s->args.count_passes = 0;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,408 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-abstract.h"
|
||||
|
||||
typedef struct lws_abstxp_raw_skt_priv {
|
||||
struct lws_abs *abs;
|
||||
struct lws *wsi;
|
||||
|
||||
lws_dll2_t same_abs_transport_list;
|
||||
|
||||
uint8_t established:1;
|
||||
uint8_t connecting:1;
|
||||
} abs_raw_skt_priv_t;
|
||||
|
||||
struct vhd {
|
||||
lws_dll2_owner_t owner;
|
||||
};
|
||||
|
||||
static int
|
||||
heartbeat_cb(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
abs_raw_skt_priv_t *priv = lws_container_of(d, abs_raw_skt_priv_t,
|
||||
same_abs_transport_list);
|
||||
|
||||
if (priv->abs->ap->heartbeat)
|
||||
priv->abs->ap->heartbeat(priv->abs->api);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
callback_abs_client_raw_skt(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)user;
|
||||
struct vhd *vhd = (struct vhd *)
|
||||
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi), sizeof(struct vhd));
|
||||
if (!vhd)
|
||||
return 1;
|
||||
lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi),
|
||||
LWS_CALLBACK_USER, 1);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_USER:
|
||||
/*
|
||||
* This comes at 1Hz without a wsi context, so there is no
|
||||
* valid priv. We need to track the live abstract objects that
|
||||
* are using our abstract protocol, and pass the heartbeat
|
||||
* through to the ones that care.
|
||||
*/
|
||||
if (!vhd)
|
||||
break;
|
||||
|
||||
lws_dll2_foreach_safe(&vhd->owner, NULL, heartbeat_cb);
|
||||
|
||||
lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi),
|
||||
LWS_CALLBACK_USER, 1);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_CONNECTED:
|
||||
lwsl_debug("LWS_CALLBACK_RAW_CONNECTED\n");
|
||||
priv->connecting = 0;
|
||||
priv->established = 1;
|
||||
if (priv->abs->ap->accept)
|
||||
priv->abs->ap->accept(priv->abs->api);
|
||||
if (wsi->seq)
|
||||
/*
|
||||
* we are bound to a sequencer who wants to know about
|
||||
* our lifecycle events
|
||||
*/
|
||||
|
||||
lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONNECTED,
|
||||
wsi, NULL);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
lwsl_user("CONNECTION_ERROR\n");
|
||||
if (in)
|
||||
lwsl_user(" %s\n", (const char *)in);
|
||||
|
||||
if (wsi->seq)
|
||||
/*
|
||||
* we are bound to a sequencer who wants to know about
|
||||
* our lifecycle events
|
||||
*/
|
||||
|
||||
lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONN_FAIL,
|
||||
wsi, NULL);
|
||||
|
||||
goto close_path;
|
||||
|
||||
/* fallthru */
|
||||
case LWS_CALLBACK_RAW_CLOSE:
|
||||
if (!user)
|
||||
break;
|
||||
|
||||
if (wsi->seq)
|
||||
/*
|
||||
* we are bound to a sequencer who wants to know about
|
||||
* our lifecycle events
|
||||
*/
|
||||
|
||||
lws_seq_queue_event(wsi->seq, LWSSEQ_WSI_CONN_CLOSE,
|
||||
wsi, NULL);
|
||||
|
||||
close_path:
|
||||
lwsl_debug("LWS_CALLBACK_RAW_CLOSE\n");
|
||||
priv->established = 0;
|
||||
priv->connecting = 0;
|
||||
if (priv->abs && priv->abs->ap->closed)
|
||||
priv->abs->ap->closed(priv->abs->api);
|
||||
lws_set_wsi_user(wsi, NULL);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_RX:
|
||||
lwsl_debug("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
|
||||
return !!priv->abs->ap->rx(priv->abs->api, in, len);
|
||||
|
||||
case LWS_CALLBACK_RAW_WRITEABLE:
|
||||
lwsl_debug("LWS_CALLBACK_RAW_WRITEABLE\n");
|
||||
priv->abs->ap->writeable(priv->abs->api,
|
||||
lws_get_peer_write_allowance(priv->wsi));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL:
|
||||
lws_dll2_add_tail(&priv->same_abs_transport_list, &vhd->owner);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL:
|
||||
lws_dll2_remove(&priv->same_abs_transport_list);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcrs_close(lws_abs_transport_inst_t *ati)
|
||||
{
|
||||
abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
|
||||
struct lws *wsi = priv->wsi;
|
||||
|
||||
if (!priv->wsi)
|
||||
return 0;
|
||||
|
||||
if (!lws_raw_transaction_completed(priv->wsi))
|
||||
return 0;
|
||||
|
||||
priv->wsi = NULL;
|
||||
lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
|
||||
|
||||
/* priv is destroyed in the CLOSE callback */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const struct lws_protocols protocol_abs_client_raw_skt = {
|
||||
"lws-abs-cli-raw-skt", callback_abs_client_raw_skt,
|
||||
0, 1024, 1024, NULL, 0
|
||||
};
|
||||
|
||||
static int
|
||||
lws_atcrs_tx(lws_abs_transport_inst_t *ati, uint8_t *buf, size_t len)
|
||||
{
|
||||
abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
|
||||
|
||||
if (!priv->wsi) {
|
||||
lwsl_err("%s: NULL priv->wsi\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: priv %p, wsi %p, ro %p\n", __func__,
|
||||
priv, priv->wsi, priv->wsi->role_ops);
|
||||
|
||||
if (lws_write(priv->wsi, buf, len, LWS_WRITE_RAW) < 0)
|
||||
lws_atcrs_close(ati);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_CLIENT)
|
||||
static int
|
||||
lws_atcrs_client_conn(const lws_abs_t *abs)
|
||||
{
|
||||
abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)abs->ati;
|
||||
struct lws_client_connect_info i;
|
||||
const lws_token_map_t *tm;
|
||||
|
||||
if (priv->connecting)
|
||||
return 0;
|
||||
|
||||
if (priv->established) {
|
||||
lws_set_timeout(priv->wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
|
||||
/* address and port are passed-in using the abstract transport tokens */
|
||||
|
||||
tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
|
||||
if (!tm) {
|
||||
lwsl_notice("%s: raw_skt needs LTMI_PEER_V_DNS_ADDRESS\n",
|
||||
__func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
i.address = tm->u.value;
|
||||
|
||||
tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_LV_PORT);
|
||||
if (!tm) {
|
||||
lwsl_notice("%s: raw_skt needs LTMI_PEER_LV_PORT\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
i.port = tm->u.lvalue;
|
||||
|
||||
/* optional */
|
||||
i.ssl_connection = 0;
|
||||
tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
|
||||
if (tm)
|
||||
i.ssl_connection = tm->u.lvalue;
|
||||
|
||||
|
||||
lwsl_debug("%s: raw_skt priv %p connecting to %s:%u %p\n",
|
||||
__func__, priv, i.address, i.port, abs->vh->context);
|
||||
|
||||
i.path = "";
|
||||
i.method = "RAW";
|
||||
i.vhost = abs->vh;
|
||||
i.userdata = priv;
|
||||
i.host = i.address;
|
||||
i.pwsi = &priv->wsi;
|
||||
i.origin = i.address;
|
||||
i.context = abs->vh->context;
|
||||
i.local_protocol_name = "lws-abs-cli-raw-skt";
|
||||
i.seq = abs->seq;
|
||||
i.opaque_user_data = abs->opaque_user_data;
|
||||
|
||||
/*
|
||||
* the protocol itself has some natural attributes we should pass on
|
||||
*/
|
||||
|
||||
if (abs->ap->flags & LWS_AP_FLAG_PIPELINE_TRANSACTIONS)
|
||||
i.ssl_connection |= LCCSCF_PIPELINE;
|
||||
|
||||
if (abs->ap->flags & LWS_AP_FLAG_MUXABLE_STREAM)
|
||||
i.ssl_connection |= LCCSCF_MUXABLE_STREAM;
|
||||
|
||||
priv->wsi = lws_client_connect_via_info(&i);
|
||||
if (!priv->wsi)
|
||||
return 1;
|
||||
|
||||
priv->connecting = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
lws_atcrs_ask_for_writeable(lws_abs_transport_inst_t *ati)
|
||||
{
|
||||
abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
|
||||
|
||||
if (!priv->wsi || !priv->established)
|
||||
return 1;
|
||||
|
||||
lws_callback_on_writable(priv->wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcrs_create(struct lws_abs *ai)
|
||||
{
|
||||
abs_raw_skt_priv_t *at = (abs_raw_skt_priv_t *)ai->ati;
|
||||
|
||||
memset(at, 0, sizeof(*at));
|
||||
at->abs = ai;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_atcrs_destroy(lws_abs_transport_inst_t **pati)
|
||||
{
|
||||
/*
|
||||
* For ourselves, we don't free anything because the abstract layer
|
||||
* combined our allocation with that of the abs instance, and it will
|
||||
* free the whole thing after this.
|
||||
*/
|
||||
*pati = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcrs_set_timeout(lws_abs_transport_inst_t *ati, int reason, int secs)
|
||||
{
|
||||
abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
|
||||
|
||||
lws_set_timeout(priv->wsi, reason, secs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcrs_state(lws_abs_transport_inst_t *ati)
|
||||
{
|
||||
abs_raw_skt_priv_t *priv = (abs_raw_skt_priv_t *)ati;
|
||||
|
||||
if (!priv || !priv->wsi || (!priv->established && !priv->connecting))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcrs_compare(lws_abs_t *abs1, lws_abs_t *abs2)
|
||||
{
|
||||
const lws_token_map_t *tm1, *tm2;
|
||||
|
||||
tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
|
||||
tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
|
||||
|
||||
/* Address token is mandatory and must match */
|
||||
if (!tm1 || !tm2 || strcmp(tm1->u.value, tm2->u.value))
|
||||
return 1;
|
||||
|
||||
/* Port token is mandatory and must match */
|
||||
tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_LV_PORT);
|
||||
tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_LV_PORT);
|
||||
if (!tm1 || !tm2 || tm1->u.lvalue != tm2->u.lvalue)
|
||||
return 1;
|
||||
|
||||
/* TLS is optional... */
|
||||
tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
|
||||
tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
|
||||
|
||||
/* ... but both must have the same situation with it given or not... */
|
||||
if (!!tm1 != !!tm2)
|
||||
return 1;
|
||||
|
||||
/* if not using TLS, then that's enough to call it */
|
||||
if (!tm1)
|
||||
return 0;
|
||||
|
||||
/* ...and if there are tls flags, both must have the same tls flags */
|
||||
if (tm1->u.lvalue != tm2->u.lvalue)
|
||||
return 1;
|
||||
|
||||
/* ... and both must use the same client tls ctx / vhost */
|
||||
return abs1->vh != abs2->vh;
|
||||
}
|
||||
|
||||
const lws_abs_transport_t lws_abs_transport_cli_raw_skt = {
|
||||
.name = "raw_skt",
|
||||
.alloc = sizeof(abs_raw_skt_priv_t),
|
||||
|
||||
.create = lws_atcrs_create,
|
||||
.destroy = lws_atcrs_destroy,
|
||||
.compare = lws_atcrs_compare,
|
||||
|
||||
.tx = lws_atcrs_tx,
|
||||
#if !defined(LWS_WITH_CLIENT)
|
||||
.client_conn = NULL,
|
||||
#else
|
||||
.client_conn = lws_atcrs_client_conn,
|
||||
#endif
|
||||
.close = lws_atcrs_close,
|
||||
.ask_for_writeable = lws_atcrs_ask_for_writeable,
|
||||
.set_timeout = lws_atcrs_set_timeout,
|
||||
.state = lws_atcrs_state,
|
||||
};
|
|
@ -1,540 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*
|
||||
* An abstract transport that is useful for unit testing an abstract protocol.
|
||||
* It doesn't actually connect to anything, but checks the protocol's response
|
||||
* to provided canned packets from an array of test vectors.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
#include "private-lib-abstract.h"
|
||||
|
||||
/* this is the transport priv instantiated at abs->ati */
|
||||
|
||||
typedef struct lws_abstxp_unit_test_priv {
|
||||
char note[128];
|
||||
struct lws_abs *abs;
|
||||
|
||||
struct lws_sequencer *seq;
|
||||
lws_unit_test_t *current_test;
|
||||
lws_unit_test_packet_t *expect;
|
||||
lws_unit_test_packet_test_cb result_cb;
|
||||
const void *result_cb_arg;
|
||||
|
||||
lws_unit_test_packet_disposition disposition;
|
||||
/* synthesized protocol timeout */
|
||||
time_t timeout;
|
||||
|
||||
uint8_t established:1;
|
||||
uint8_t connecting:1;
|
||||
} abs_unit_test_priv_t;
|
||||
|
||||
typedef struct seq_priv {
|
||||
lws_abs_t *ai;
|
||||
} seq_priv_t;
|
||||
|
||||
enum {
|
||||
UTSEQ_MSG_WRITEABLE = LWSSEQ_USER_BASE,
|
||||
UTSEQ_MSG_CLOSING,
|
||||
UTSEQ_MSG_TIMEOUT,
|
||||
UTSEQ_MSG_CONNECTING,
|
||||
UTSEQ_MSG_POST_TX_KICK,
|
||||
UTSEQ_MSG_DISPOSITION_KNOWN
|
||||
};
|
||||
|
||||
/*
|
||||
* A definitive result has appeared for the current test
|
||||
*/
|
||||
|
||||
static lws_unit_test_packet_disposition
|
||||
lws_unit_test_packet_dispose(abs_unit_test_priv_t *priv,
|
||||
lws_unit_test_packet_disposition disp,
|
||||
const char *note)
|
||||
{
|
||||
assert(priv->disposition == LPE_CONTINUE);
|
||||
|
||||
lwsl_info("%s: %d\n", __func__, disp);
|
||||
|
||||
if (note)
|
||||
lws_strncpy(priv->note, note, sizeof(priv->note));
|
||||
|
||||
priv->disposition = disp;
|
||||
|
||||
lws_seq_queue_event(priv->seq, UTSEQ_MSG_DISPOSITION_KNOWN,
|
||||
NULL, NULL);
|
||||
|
||||
return disp;
|
||||
}
|
||||
|
||||
/*
|
||||
* start on the next step of the test
|
||||
*/
|
||||
|
||||
lws_unit_test_packet_disposition
|
||||
process_expect(abs_unit_test_priv_t *priv)
|
||||
{
|
||||
assert(priv->disposition == LPE_CONTINUE);
|
||||
|
||||
while (priv->expect->flags & LWS_AUT_EXPECT_RX &&
|
||||
priv->disposition == LPE_CONTINUE) {
|
||||
int f = priv->expect->flags & LWS_AUT_EXPECT_LOCAL_CLOSE, s;
|
||||
|
||||
if (priv->expect->pre)
|
||||
priv->expect->pre(priv->abs);
|
||||
|
||||
lwsl_info("%s: rx()\n", __func__);
|
||||
lwsl_hexdump_debug(priv->expect->buffer, priv->expect->len);
|
||||
s = priv->abs->ap->rx(priv->abs->api, priv->expect->buffer,
|
||||
priv->expect->len);
|
||||
|
||||
if (!!f != !!s) {
|
||||
lwsl_notice("%s: expected rx return %d, got %d\n",
|
||||
__func__, !!f, s);
|
||||
|
||||
return lws_unit_test_packet_dispose(priv, LPE_FAILED,
|
||||
"rx unexpected return");
|
||||
}
|
||||
|
||||
if (priv->expect->flags & LWS_AUT_EXPECT_TEST_END) {
|
||||
lws_unit_test_packet_dispose(priv, LPE_SUCCEEDED, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
priv->expect++;
|
||||
}
|
||||
|
||||
return LPE_CONTINUE;
|
||||
}
|
||||
|
||||
static lws_seq_cb_return_t
|
||||
unit_test_sequencer_cb(struct lws_sequencer *seq, void *user, int event,
|
||||
void *data, void *aux)
|
||||
{
|
||||
seq_priv_t *s = (seq_priv_t *)user;
|
||||
abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)s->ai->ati;
|
||||
time_t now;
|
||||
|
||||
switch ((int)event) {
|
||||
case LWSSEQ_CREATED: /* our sequencer just got started */
|
||||
lwsl_notice("%s: %s: created\n", __func__,
|
||||
lws_seq_name(seq));
|
||||
if (s->ai->at->client_conn(s->ai)) {
|
||||
lwsl_notice("%s: %s: abstract client conn failed\n",
|
||||
__func__, lws_seq_name(seq));
|
||||
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWSSEQ_DESTROYED:
|
||||
/*
|
||||
* This sequencer is about to be destroyed. If we have any
|
||||
* other assets in play, detach them from us.
|
||||
*/
|
||||
|
||||
if (priv->abs)
|
||||
lws_abs_destroy_instance(&priv->abs);
|
||||
|
||||
break;
|
||||
|
||||
case LWSSEQ_HEARTBEAT:
|
||||
|
||||
/* synthesize a wsi-style timeout */
|
||||
|
||||
if (!priv->timeout)
|
||||
goto ph;
|
||||
|
||||
time(&now);
|
||||
|
||||
if (now <= priv->timeout)
|
||||
goto ph;
|
||||
|
||||
if (priv->expect->flags & LWS_AUT_EXPECT_SHOULD_TIMEOUT) {
|
||||
lwsl_user("%s: test got expected timeout\n",
|
||||
__func__);
|
||||
lws_unit_test_packet_dispose(priv,
|
||||
LPE_FAILED_UNEXPECTED_TIMEOUT, NULL);
|
||||
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
}
|
||||
lwsl_user("%s: seq timed out\n", __func__);
|
||||
|
||||
ph:
|
||||
if (priv->abs->ap->heartbeat)
|
||||
priv->abs->ap->heartbeat(priv->abs->api);
|
||||
break;
|
||||
|
||||
case UTSEQ_MSG_DISPOSITION_KNOWN:
|
||||
|
||||
lwsl_info("%s: %s: DISPOSITION_KNOWN %s: %s\n", __func__,
|
||||
priv->abs->ap->name,
|
||||
priv->current_test->name,
|
||||
priv->disposition == LPE_SUCCEEDED ? "OK" : "FAIL");
|
||||
|
||||
/*
|
||||
* if the test has a callback, call it back to let it
|
||||
* know the result
|
||||
*/
|
||||
if (priv->result_cb)
|
||||
priv->result_cb(priv->result_cb_arg, priv->disposition);
|
||||
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
|
||||
case UTSEQ_MSG_CONNECTING:
|
||||
lwsl_debug("UTSEQ_MSG_CONNECTING\n");
|
||||
|
||||
if (priv->abs->ap->accept)
|
||||
priv->abs->ap->accept(priv->abs->api);
|
||||
|
||||
priv->established = 1;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case UTSEQ_MSG_POST_TX_KICK:
|
||||
if (priv->disposition)
|
||||
break;
|
||||
|
||||
if (process_expect(priv) != LPE_CONTINUE) {
|
||||
lwsl_notice("%s: UTSEQ_MSG_POST_TX_KICK failed\n",
|
||||
__func__);
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
}
|
||||
break;
|
||||
|
||||
case UTSEQ_MSG_WRITEABLE:
|
||||
/*
|
||||
* inform the protocol our transport is writeable now
|
||||
*/
|
||||
priv->abs->ap->writeable(priv->abs->api, 1024);
|
||||
break;
|
||||
|
||||
case UTSEQ_MSG_CLOSING:
|
||||
|
||||
if (!(priv->expect->flags & LWS_AUT_EXPECT_LOCAL_CLOSE)) {
|
||||
lwsl_user("%s: got unexpected close\n", __func__);
|
||||
|
||||
lws_unit_test_packet_dispose(priv,
|
||||
LPE_FAILED_UNEXPECTED_CLOSE, NULL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* tell the abstract protocol we are closing on them */
|
||||
|
||||
if (priv->abs && priv->abs->ap->closed)
|
||||
priv->abs->ap->closed(priv->abs->api);
|
||||
|
||||
goto done;
|
||||
|
||||
case UTSEQ_MSG_TIMEOUT: /* current step timed out */
|
||||
|
||||
s->ai->at->close(s->ai->ati);
|
||||
|
||||
if (!(priv->expect->flags & LWS_AUT_EXPECT_SHOULD_TIMEOUT)) {
|
||||
lwsl_user("%s: got unexpected timeout\n", __func__);
|
||||
|
||||
lws_unit_test_packet_dispose(priv,
|
||||
LPE_FAILED_UNEXPECTED_TIMEOUT, NULL);
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
}
|
||||
goto done;
|
||||
|
||||
done:
|
||||
lws_seq_timeout_us(lws_seq_from_user(s),
|
||||
LWSSEQTO_NONE);
|
||||
priv->expect++;
|
||||
if (!priv->expect->buffer) {
|
||||
/* the sequence has completed */
|
||||
lwsl_user("%s: sequence completed OK\n", __func__);
|
||||
|
||||
return LWSSEQ_RET_DESTROY;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return LWSSEQ_RET_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcut_close(lws_abs_transport_inst_t *ati)
|
||||
{
|
||||
abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
lws_seq_queue_event(priv->seq, UTSEQ_MSG_CLOSING, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcut_tx(lws_abs_transport_inst_t *ati, uint8_t *buf, size_t len)
|
||||
{
|
||||
abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
|
||||
|
||||
assert(priv->disposition == LPE_CONTINUE);
|
||||
|
||||
lwsl_info("%s: received tx\n", __func__);
|
||||
|
||||
if (priv->expect->pre)
|
||||
priv->expect->pre(priv->abs);
|
||||
|
||||
if (!(priv->expect->flags & LWS_AUT_EXPECT_TX)) {
|
||||
lwsl_notice("%s: unexpected tx\n", __func__);
|
||||
lwsl_hexdump_notice(buf, len);
|
||||
lws_unit_test_packet_dispose(priv, LPE_FAILED, "unexpected tx");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (len != priv->expect->len) {
|
||||
lwsl_notice("%s: unexpected tx len %zu, expected %zu\n",
|
||||
__func__, len, priv->expect->len);
|
||||
lws_unit_test_packet_dispose(priv, LPE_FAILED,
|
||||
"tx len mismatch");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (memcmp(buf, priv->expect->buffer, len)) {
|
||||
lwsl_notice("%s: tx mismatch (exp / actual)\n", __func__);
|
||||
lwsl_hexdump_debug(priv->expect->buffer, len);
|
||||
lwsl_hexdump_debug(buf, len);
|
||||
lws_unit_test_packet_dispose(priv, LPE_FAILED,
|
||||
"tx data mismatch");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (priv->expect->flags & LWS_AUT_EXPECT_TEST_END) {
|
||||
lws_unit_test_packet_dispose(priv, LPE_SUCCEEDED, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
priv->expect++;
|
||||
|
||||
lws_seq_queue_event(priv->seq, UTSEQ_MSG_POST_TX_KICK, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_CLIENT)
|
||||
static int
|
||||
lws_atcut_client_conn(const lws_abs_t *abs)
|
||||
{
|
||||
abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)abs->ati;
|
||||
const lws_token_map_t *tm;
|
||||
|
||||
if (priv->established) {
|
||||
lwsl_err("%s: already established\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* set up the test start pieces... the array of test expects... */
|
||||
|
||||
tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_V_EXPECT_TEST);
|
||||
if (!tm) {
|
||||
lwsl_notice("%s: unit_test needs LTMI_PEER_V_EXPECT_TEST\n",
|
||||
__func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
priv->current_test = (lws_unit_test_t *)tm->u.value;
|
||||
|
||||
/* ... and the callback to deliver the result to */
|
||||
tm = lws_abs_get_token(abs->at_tokens, LTMI_PEER_V_EXPECT_RESULT_CB);
|
||||
if (tm)
|
||||
priv->result_cb = (lws_unit_test_packet_test_cb)tm->u.value;
|
||||
else
|
||||
priv->result_cb = NULL;
|
||||
|
||||
/* ... and the arg to deliver it with */
|
||||
tm = lws_abs_get_token(abs->at_tokens,
|
||||
LTMI_PEER_V_EXPECT_RESULT_CB_ARG);
|
||||
if (tm)
|
||||
priv->result_cb_arg = tm->u.value;
|
||||
|
||||
priv->expect = priv->current_test->expect_array;
|
||||
priv->disposition = LPE_CONTINUE;
|
||||
priv->note[0] = '\0';
|
||||
|
||||
lws_seq_timeout_us(priv->seq, priv->current_test->max_secs *
|
||||
LWS_US_PER_SEC);
|
||||
|
||||
lwsl_notice("%s: %s: test '%s': start\n", __func__, abs->ap->name,
|
||||
priv->current_test->name);
|
||||
|
||||
lws_seq_queue_event(priv->seq, UTSEQ_MSG_CONNECTING, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
lws_atcut_ask_for_writeable(lws_abs_transport_inst_t *ati)
|
||||
{
|
||||
abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
|
||||
|
||||
if (!priv->established)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Queue a writeable event... this won't be handled by teh sequencer
|
||||
* until we have returned to the event loop, just like a real
|
||||
* callback_on_writable()
|
||||
*/
|
||||
lws_seq_queue_event(priv->seq, UTSEQ_MSG_WRITEABLE, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* An abstract protocol + transport has been instantiated
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_atcut_create(lws_abs_t *ai)
|
||||
{
|
||||
abs_unit_test_priv_t *priv;
|
||||
struct lws_sequencer *seq;
|
||||
lws_seq_info_t i;
|
||||
seq_priv_t *s;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.context = ai->vh->context;
|
||||
i.user_size = sizeof(*s);
|
||||
i.puser = (void **)&s;
|
||||
i.cb = unit_test_sequencer_cb;
|
||||
i.name = "unit-test-seq";
|
||||
|
||||
/*
|
||||
* Create the sequencer for the steps in a single unit test
|
||||
*/
|
||||
|
||||
seq = lws_seq_create(&i);
|
||||
if (!seq) {
|
||||
lwsl_err("%s: unable to create sequencer\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
priv = ai->ati;
|
||||
memset(s, 0, sizeof(*s));
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
/* the sequencer priv just points to the lws_abs_t */
|
||||
s->ai = ai;
|
||||
priv->abs = ai;
|
||||
priv->seq = seq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_atcut_destroy(lws_abs_transport_inst_t **pati)
|
||||
{
|
||||
/*
|
||||
* We don't free anything because the abstract layer combined our
|
||||
* allocation with that of the instance, and it will free the whole
|
||||
* thing after this.
|
||||
*/
|
||||
*pati = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcut_set_timeout(lws_abs_transport_inst_t *ati, int reason, int secs)
|
||||
{
|
||||
abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
|
||||
if (secs)
|
||||
priv->timeout = now + secs;
|
||||
else
|
||||
priv->timeout = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcut_state(lws_abs_transport_inst_t *ati)
|
||||
{
|
||||
abs_unit_test_priv_t *priv = (abs_unit_test_priv_t *)ati;
|
||||
|
||||
if (!priv || (!priv->established && !priv->connecting))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *dnames[] = {
|
||||
"INCOMPLETE",
|
||||
"PASS",
|
||||
"FAIL",
|
||||
"FAIL(TIMEOUT)",
|
||||
"FAIL(UNEXPECTED PASS)",
|
||||
"FAIL(UNEXPECTED CLOSE)",
|
||||
"SKIPPED"
|
||||
"?",
|
||||
"?"
|
||||
};
|
||||
|
||||
|
||||
const char *
|
||||
lws_unit_test_result_name(int in)
|
||||
{
|
||||
if (in < 0 || in > (int)LWS_ARRAY_SIZE(dnames))
|
||||
return "unknown";
|
||||
|
||||
return dnames[in];
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcut_compare(lws_abs_t *abs1, lws_abs_t *abs2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const lws_abs_transport_t lws_abs_transport_cli_unit_test = {
|
||||
.name = "unit_test",
|
||||
.alloc = sizeof(abs_unit_test_priv_t),
|
||||
|
||||
.create = lws_atcut_create,
|
||||
.destroy = lws_atcut_destroy,
|
||||
.compare = lws_atcut_compare,
|
||||
|
||||
.tx = lws_atcut_tx,
|
||||
#if !defined(LWS_WITH_CLIENT)
|
||||
.client_conn = NULL,
|
||||
#else
|
||||
.client_conn = lws_atcut_client_conn,
|
||||
#endif
|
||||
.close = lws_atcut_close,
|
||||
.ask_for_writeable = lws_atcut_ask_for_writeable,
|
||||
.set_timeout = lws_atcut_set_timeout,
|
||||
.state = lws_atcut_state,
|
||||
};
|
|
@ -56,11 +56,6 @@ if (LWS_WITH_LWS_DSH)
|
|||
core-net/lws-dsh.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SEQUENCER)
|
||||
list(APPEND SOURCES
|
||||
core-net/sequencer.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_CLIENT)
|
||||
list(APPEND SOURCES
|
||||
core-net/client/client.c
|
||||
|
|
|
@ -234,7 +234,6 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
else
|
||||
wsi->keep_warm_secs = 5;
|
||||
|
||||
wsi->seq = i->seq;
|
||||
wsi->flags = i->ssl_connection;
|
||||
|
||||
wsi->c_pri = i->priority;
|
||||
|
|
|
@ -284,7 +284,6 @@ struct lws_context_per_thread {
|
|||
pthread_t self;
|
||||
#endif
|
||||
struct lws_dll2_owner dll_buflist_owner; /* guys with pending rxflow */
|
||||
struct lws_dll2_owner seq_owner; /* list of lws_sequencer-s */
|
||||
lws_dll2_owner_t attach_owner; /* pending lws_attach */
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
|
@ -298,9 +297,6 @@ struct lws_context_per_thread {
|
|||
|
||||
struct lws_dll2_owner pt_sul_owner[LWS_COUNT_PT_SUL_OWNERS];
|
||||
|
||||
#if defined (LWS_WITH_SEQUENCER)
|
||||
lws_sorted_usec_list_t sul_seq_heartbeat;
|
||||
#endif
|
||||
#if (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)) && defined(LWS_WITH_SERVER)
|
||||
lws_sorted_usec_list_t sul_ah_lifecheck;
|
||||
#endif
|
||||
|
@ -701,7 +697,6 @@ struct lws {
|
|||
struct lws *child_list; /* points to first child */
|
||||
struct lws *sibling_list; /* subsequent children at same level */
|
||||
const struct lws_role_ops *role_ops;
|
||||
struct lws_sequencer *seq; /* associated sequencer if any */
|
||||
const lws_retry_bo_t *retry_policy;
|
||||
|
||||
lws_log_cx_t *log_cx;
|
||||
|
|
|
@ -1,335 +0,0 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
|
||||
/*
|
||||
* per pending event
|
||||
*/
|
||||
typedef struct lws_seq_event {
|
||||
struct lws_dll2 seq_event_list;
|
||||
|
||||
void *data;
|
||||
void *aux;
|
||||
lws_seq_events_t e;
|
||||
} lws_seq_event_t;
|
||||
|
||||
/*
|
||||
* per sequencer
|
||||
*/
|
||||
typedef struct lws_sequencer {
|
||||
struct lws_dll2 seq_list;
|
||||
|
||||
lws_sorted_usec_list_t sul_timeout;
|
||||
lws_sorted_usec_list_t sul_pending;
|
||||
|
||||
struct lws_dll2_owner seq_event_owner;
|
||||
struct lws_context_per_thread *pt;
|
||||
lws_seq_event_cb cb;
|
||||
const char *name;
|
||||
const lws_retry_bo_t *retry;
|
||||
|
||||
lws_usec_t time_created;
|
||||
lws_usec_t timeout; /* 0 or time we timeout */
|
||||
|
||||
uint8_t going_down:1;
|
||||
uint8_t wakesuspend:1;
|
||||
} lws_seq_t;
|
||||
|
||||
#define QUEUE_SANITY_LIMIT 10
|
||||
|
||||
static void
|
||||
lws_sul_seq_heartbeat_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
struct lws_context_per_thread *pt = lws_container_of(sul,
|
||||
struct lws_context_per_thread, sul_seq_heartbeat);
|
||||
|
||||
/* send every sequencer a heartbeat message... it can ignore it */
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
|
||||
lws_dll2_get_head(&pt->seq_owner)) {
|
||||
lws_seq_t *s = lws_container_of(p, lws_seq_t, seq_list);
|
||||
|
||||
/* queue the message to inform the sequencer */
|
||||
lws_seq_queue_event(s, LWSSEQ_HEARTBEAT, NULL, NULL);
|
||||
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
|
||||
/* schedule the next one */
|
||||
|
||||
__lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
|
||||
&pt->sul_seq_heartbeat, LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
int
|
||||
lws_seq_pt_init(struct lws_context_per_thread *pt)
|
||||
{
|
||||
pt->sul_seq_heartbeat.cb = lws_sul_seq_heartbeat_cb;
|
||||
|
||||
/* schedule the first heartbeat */
|
||||
__lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
|
||||
&pt->sul_seq_heartbeat, LWS_US_PER_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_seq_t *
|
||||
lws_seq_create(lws_seq_info_t *i)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &i->context->pt[i->tsi];
|
||||
lws_seq_t *seq = lws_zalloc(sizeof(*seq) + i->user_size, __func__);
|
||||
|
||||
if (!seq)
|
||||
return NULL;
|
||||
|
||||
seq->cb = i->cb;
|
||||
seq->pt = pt;
|
||||
seq->name = i->name;
|
||||
seq->retry = i->retry;
|
||||
seq->wakesuspend = i->wakesuspend;
|
||||
|
||||
*i->puser = (void *)&seq[1];
|
||||
|
||||
/* add the sequencer to the pt */
|
||||
|
||||
lws_pt_lock(pt, __func__); /* ---------------------------------- pt { */
|
||||
|
||||
lws_dll2_add_tail(&seq->seq_list, &pt->seq_owner);
|
||||
|
||||
lws_pt_unlock(pt); /* } pt ------------------------------------------ */
|
||||
|
||||
seq->time_created = lws_now_usecs();
|
||||
|
||||
/* try to queue the creation cb */
|
||||
|
||||
if (lws_seq_queue_event(seq, LWSSEQ_CREATED, NULL, NULL)) {
|
||||
lws_dll2_remove(&seq->seq_list);
|
||||
lws_free(seq);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
static int
|
||||
seq_ev_destroy(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_seq_event_t *seqe = lws_container_of(d, lws_seq_event_t,
|
||||
seq_event_list);
|
||||
|
||||
lws_dll2_remove(&seqe->seq_event_list);
|
||||
lws_free(seqe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_seq_destroy(lws_seq_t **pseq)
|
||||
{
|
||||
lws_seq_t *seq = *pseq;
|
||||
|
||||
/* defeat another thread racing to add events while we are destroying */
|
||||
seq->going_down = 1;
|
||||
|
||||
seq->cb(seq, (void *)&seq[1], LWSSEQ_DESTROYED, NULL, NULL);
|
||||
|
||||
lws_pt_lock(seq->pt, __func__); /* -------------------------- pt { */
|
||||
|
||||
lws_dll2_remove(&seq->seq_list);
|
||||
lws_dll2_remove(&seq->sul_timeout.list);
|
||||
lws_dll2_remove(&seq->sul_pending.list);
|
||||
/* remove and destroy any pending events */
|
||||
lws_dll2_foreach_safe(&seq->seq_event_owner, NULL, seq_ev_destroy);
|
||||
|
||||
lws_pt_unlock(seq->pt); /* } pt ---------------------------------- */
|
||||
|
||||
|
||||
lws_free_set_NULL(seq);
|
||||
}
|
||||
|
||||
void
|
||||
lws_seq_destroy_all_on_pt(struct lws_context_per_thread *pt)
|
||||
{
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
|
||||
pt->seq_owner.head) {
|
||||
lws_seq_t *s = lws_container_of(p, lws_seq_t,
|
||||
seq_list);
|
||||
|
||||
lws_seq_destroy(&s);
|
||||
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_seq_sul_pending_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
lws_seq_t *seq = lws_container_of(sul, lws_seq_t, sul_pending);
|
||||
lws_seq_event_t *seqe;
|
||||
struct lws_dll2 *dh;
|
||||
int n;
|
||||
|
||||
if (!seq->seq_event_owner.count)
|
||||
return;
|
||||
|
||||
/* events are only added at tail, so no race possible yet... */
|
||||
|
||||
dh = lws_dll2_get_head(&seq->seq_event_owner);
|
||||
seqe = lws_container_of(dh, lws_seq_event_t, seq_event_list);
|
||||
|
||||
n = (int)seq->cb(seq, (void *)&seq[1], (int)seqe->e, seqe->data, seqe->aux);
|
||||
|
||||
/* ... have to lock here though, because we will change the list */
|
||||
|
||||
lws_pt_lock(seq->pt, __func__); /* ----------------------------- pt { */
|
||||
|
||||
/* detach event from sequencer event list and free it */
|
||||
lws_dll2_remove(&seqe->seq_event_list);
|
||||
lws_free(seqe);
|
||||
lws_pt_unlock(seq->pt); /* } pt ------------------------------------- */
|
||||
|
||||
if (n) {
|
||||
lwsl_info("%s: destroying seq '%s' by request\n", __func__,
|
||||
seq->name);
|
||||
lws_seq_destroy(&seq);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
lws_seq_queue_event(lws_seq_t *seq, lws_seq_events_t e, void *data, void *aux)
|
||||
{
|
||||
lws_seq_event_t *seqe;
|
||||
|
||||
if (!seq || seq->going_down)
|
||||
return 1;
|
||||
|
||||
seqe = lws_zalloc(sizeof(*seqe), __func__);
|
||||
if (!seqe)
|
||||
return 1;
|
||||
|
||||
seqe->e = e;
|
||||
seqe->data = data;
|
||||
seqe->aux = aux;
|
||||
|
||||
// lwsl_notice("%s: seq %s: event %d\n", __func__, seq->name, e);
|
||||
|
||||
lws_pt_lock(seq->pt, __func__); /* ----------------------------- pt { */
|
||||
|
||||
if (seq->seq_event_owner.count > QUEUE_SANITY_LIMIT) {
|
||||
lwsl_err("%s: more than %d events queued\n", __func__,
|
||||
QUEUE_SANITY_LIMIT);
|
||||
}
|
||||
|
||||
lws_dll2_add_tail(&seqe->seq_event_list, &seq->seq_event_owner);
|
||||
|
||||
seq->sul_pending.cb = lws_seq_sul_pending_cb;
|
||||
__lws_sul_insert_us(&seq->pt->pt_sul_owner[seq->wakesuspend],
|
||||
&seq->sul_pending, 1);
|
||||
|
||||
lws_pt_unlock(seq->pt); /* } pt ------------------------------------- */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if wsi still extant, by peeking in the message queue for a
|
||||
* LWSSEQ_WSI_CONN_CLOSE message about wsi. (Doesn't need to do the same for
|
||||
* CONN_FAIL since that will never have produced any messages prior to that).
|
||||
*
|
||||
* Use this to avoid trying to perform operations on wsi that have already
|
||||
* closed but we didn't get to that message yet.
|
||||
*
|
||||
* Returns 0 if not closed yet or 1 if it has closed but we didn't process the
|
||||
* close message yet.
|
||||
*/
|
||||
|
||||
int
|
||||
lws_seq_check_wsi(lws_seq_t *seq, struct lws *wsi)
|
||||
{
|
||||
lws_seq_event_t *seqe;
|
||||
struct lws_dll2 *dh;
|
||||
|
||||
lws_pt_lock(seq->pt, __func__); /* ----------------------------- pt { */
|
||||
|
||||
dh = lws_dll2_get_head(&seq->seq_event_owner);
|
||||
while (dh) {
|
||||
seqe = lws_container_of(dh, lws_seq_event_t, seq_event_list);
|
||||
|
||||
if (seqe->e == LWSSEQ_WSI_CONN_CLOSE && seqe->data == wsi)
|
||||
break;
|
||||
|
||||
dh = dh->next;
|
||||
}
|
||||
|
||||
lws_pt_unlock(seq->pt); /* } pt ------------------------------------- */
|
||||
|
||||
return !!dh;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lws_seq_sul_timeout_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
lws_seq_t *s = lws_container_of(sul, lws_seq_t, sul_timeout);
|
||||
|
||||
lws_seq_queue_event(s, LWSSEQ_TIMED_OUT, NULL, NULL);
|
||||
}
|
||||
|
||||
/* set us to LWS_SET_TIMER_USEC_CANCEL to remove timeout */
|
||||
|
||||
int
|
||||
lws_seq_timeout_us(lws_seq_t *seq, lws_usec_t us)
|
||||
{
|
||||
seq->sul_timeout.cb = lws_seq_sul_timeout_cb;
|
||||
/* list is always at the very top of the sul */
|
||||
__lws_sul_insert_us(&seq->pt->pt_sul_owner[seq->wakesuspend],
|
||||
(lws_sorted_usec_list_t *)&seq->sul_timeout.list, us);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_seq_t *
|
||||
lws_seq_from_user(void *u)
|
||||
{
|
||||
return &((lws_seq_t *)u)[-1];
|
||||
}
|
||||
|
||||
const char *
|
||||
lws_seq_name(lws_seq_t *seq)
|
||||
{
|
||||
return seq->name;
|
||||
}
|
||||
|
||||
lws_usec_t
|
||||
lws_seq_us_since_creation(lws_seq_t *seq)
|
||||
{
|
||||
return lws_now_usecs() - seq->time_created;
|
||||
}
|
||||
|
||||
struct lws_context *
|
||||
lws_seq_get_context(lws_seq_t *seq)
|
||||
{
|
||||
return seq->pt->context;
|
||||
}
|
||||
|
|
@ -1140,9 +1140,6 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
context->pt[n].http.ah_pool_length = 0;
|
||||
#endif
|
||||
lws_pt_mutex_init(&context->pt[n]);
|
||||
#if defined(LWS_WITH_SEQUENCER)
|
||||
lws_seq_pt_init(&context->pt[n]);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_CGI)
|
||||
if (lws_rops_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy))
|
||||
|
@ -1712,11 +1709,6 @@ lws_pt_destroy(struct lws_context_per_thread *pt)
|
|||
lws_dll2_foreach_safe(&pt->ss_client_owner, NULL, lws_sspc_destroy_dll);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SEQUENCER)
|
||||
lws_seq_destroy_all_on_pt(pt);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
while (pt->http.ah_list)
|
||||
_lws_destroy_ah(pt, pt->http.ah_list);
|
||||
|
@ -2048,9 +2040,7 @@ next:
|
|||
struct lws_context_per_thread *pt = &context->pt[n];
|
||||
|
||||
(void)pt;
|
||||
#if defined(LWS_WITH_SEQUENCER)
|
||||
lws_seq_destroy_all_on_pt(pt);
|
||||
#endif
|
||||
|
||||
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
|
||||
if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy))
|
||||
(lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)).
|
||||
|
|
|
@ -76,7 +76,6 @@ typedef struct lws_ss_handle {
|
|||
struct lws_context *context; /**< lws context we are created on */
|
||||
const lws_ss_policy_t *policy; /**< system policy for stream */
|
||||
|
||||
struct lws_sequencer *seq; /**< owning sequencer if any */
|
||||
struct lws *wsi; /**< the stream wsi if any */
|
||||
|
||||
struct lws_sss_proxy_conn *conn_if_sspc_onw;
|
||||
|
|
|
@ -417,16 +417,6 @@ lws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs)
|
|||
if (cs == LWSSSCS_DISCONNECTED)
|
||||
h->ss_dangling_connected = 0;
|
||||
|
||||
#if defined(LWS_WITH_SEQUENCER)
|
||||
/*
|
||||
* A parent sequencer for the ss is optional, if we have one, keep it
|
||||
* informed of state changes on the ss connection
|
||||
*/
|
||||
if (h->seq && cs != LWSSSCS_DESTROYING)
|
||||
lws_seq_queue_event(h->seq, LWSSEQ_SS_STATE_BASE + cs,
|
||||
(void *)h, NULL);
|
||||
#endif
|
||||
|
||||
if (h->info.state) {
|
||||
h->h_in_svc = h;
|
||||
r = h->info.state(ss_to_userobj(h), NULL, cs,
|
||||
|
@ -820,7 +810,6 @@ _lws_ss_client_connect(lws_ss_handle_t *h, int is_retry, void *conn_if_sspc_onw)
|
|||
i.host = i.address;
|
||||
i.origin = i.address;
|
||||
i.opaque_user_data = h;
|
||||
i.seq = h->seq;
|
||||
i.retry_and_idle_policy = h->policy->retry_bo;
|
||||
i.sys_tls_client_cert = h->policy->client_cert;
|
||||
|
||||
|
@ -938,7 +927,7 @@ lws_ss_client_connect(lws_ss_handle_t *h)
|
|||
int
|
||||
lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
||||
void *opaque_user_data, lws_ss_handle_t **ppss,
|
||||
struct lws_sequencer *seq_owner, const char **ppayload_fmt)
|
||||
void *reserved, const char **ppayload_fmt)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
const lws_ss_policy_t *pol;
|
||||
|
@ -1068,7 +1057,6 @@ lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
|||
h->policy = pol;
|
||||
h->context = context;
|
||||
h->tsi = (uint8_t)tsi;
|
||||
h->seq = seq_owner;
|
||||
|
||||
if (h->info.flags & LWSSSINFLAGS_PROXIED)
|
||||
h->proxy_onward = 1;
|
||||
|
@ -1678,12 +1666,6 @@ lws_ss_cancel_notify_dll(struct lws_dll2 *d, void *user)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct lws_sequencer *
|
||||
lws_ss_get_sequencer(lws_ss_handle_t *h)
|
||||
{
|
||||
return h->seq;
|
||||
}
|
||||
|
||||
struct lws_context *
|
||||
lws_ss_get_context(struct lws_ss_handle *h)
|
||||
{
|
||||
|
|
|
@ -282,7 +282,7 @@ lws_sspc_event_helper(lws_sspc_handle_t *h, lws_ss_constate_t cs,
|
|||
int
|
||||
lws_sspc_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
|
||||
void *opaque_user_data, lws_sspc_handle_t **ppss,
|
||||
struct lws_sequencer *seq_owner, const char **ppayload_fmt)
|
||||
void *reserved, const char **ppayload_fmt)
|
||||
{
|
||||
lws_sspc_handle_t *h;
|
||||
uint8_t *ua;
|
||||
|
|
Loading…
Add table
Reference in a new issue