mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
smtp: make abstract
This commit is contained in:
parent
ae6346db64
commit
8d473ad78c
29 changed files with 1630 additions and 624 deletions
|
@ -346,11 +346,6 @@ message(STATUS "LWS_WITH_PLUGINS --> Enabling LWS_WITH_LIBUV")
|
|||
set(LWS_WITH_LIBUV 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SMTP AND NOT LWS_WITH_LIBUV)
|
||||
message(STATUS "LWS_WITH_SMTP --> Enabling LWS_WITH_LIBUV")
|
||||
set(LWS_WITH_LIBUV 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_PLUGINS OR LWS_WITH_CGI)
|
||||
# sshd plugin
|
||||
set(LWS_WITH_GENCRYPTO 1)
|
||||
|
@ -361,11 +356,6 @@ if (LWS_WITH_GENERIC_SESSIONS)
|
|||
set(LWS_WITH_SMTP 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SMTP AND NOT LWS_WITH_LIBUV)
|
||||
message(STATUS "LWS_WITH_SMTP --> Enabling LWS_WITH_LIBUV")
|
||||
set(LWS_WITH_LIBUV 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_ESP32)
|
||||
set(LWS_WITH_SHARED OFF)
|
||||
set(LWS_WITH_MBEDTLS ON)
|
||||
|
@ -929,6 +919,7 @@ if (LWS_WITH_NETWORK)
|
|||
lib/core-net/wsi-timeout.c
|
||||
lib/core-net/adopt.c
|
||||
lib/roles/pipe/ops-pipe.c
|
||||
lib/abstract/abstract.c
|
||||
)
|
||||
|
||||
if (LWS_WITH_STATS)
|
||||
|
@ -982,6 +973,7 @@ endif()
|
|||
|
||||
if (LWS_ROLE_RAW)
|
||||
list(APPEND SOURCES
|
||||
lib/abstract/transports/raw-skt.c
|
||||
lib/roles/raw-skt/ops-raw-skt.c
|
||||
lib/roles/raw-file/ops-raw-file.c)
|
||||
endif()
|
||||
|
@ -1295,7 +1287,7 @@ endif()
|
|||
|
||||
if (LWS_WITH_SMTP)
|
||||
list(APPEND SOURCES
|
||||
lib/misc/smtp.c)
|
||||
lib/abstract/smtp/smtp.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_RANGES)
|
||||
|
|
|
@ -529,6 +529,9 @@ struct lws;
|
|||
#include <libwebsockets/lws-fts.h>
|
||||
#include <libwebsockets/lws-diskcache.h>
|
||||
|
||||
#include <libwebsockets/abstract/transports.h>
|
||||
#include <libwebsockets/abstract/smtp.h>
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
|
|
164
include/libwebsockets/abstract/smtp.h
Normal file
164
include/libwebsockets/abstract/smtp.h
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* included from libwebsockets.h
|
||||
*/
|
||||
|
||||
/** \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.
|
||||
*
|
||||
* It runs via its own libuv events if initialized (which requires giving it
|
||||
* a libuv loop to attach to).
|
||||
*
|
||||
* It operates using three callbacks, on_next() queries if there is a new email
|
||||
* to send, on_get_body() asks for the body of the email, and on_sent() is
|
||||
* called after the email is successfully sent.
|
||||
*
|
||||
* To use it
|
||||
*
|
||||
* - create an lws_email struct
|
||||
*
|
||||
* - initialize data, loop, the email_* strings, max_content_size and
|
||||
* the callbacks
|
||||
*
|
||||
* - call lws_email_init()
|
||||
*
|
||||
* When you have at least one email to send, call lws_email_check() to
|
||||
* schedule starting to send it.
|
||||
*/
|
||||
//@{
|
||||
#if defined(LWS_WITH_SMTP)
|
||||
|
||||
typedef struct lws_smtp_client lws_smtp_client_t;
|
||||
typedef struct lws_abstract lws_abstract_t;
|
||||
|
||||
typedef struct lws_smtp_client_info {
|
||||
void *data;
|
||||
|
||||
char ip[32]; /**< Fill before init, eg, "127.0.0.1" */
|
||||
char helo[32]; /**< Fill before init, eg, "myserver.com" */
|
||||
|
||||
const lws_abstract_t *abs; /**< abstract transport to use */
|
||||
struct lws_vhost *vh;
|
||||
|
||||
time_t retry_interval;
|
||||
time_t delivery_timeout;
|
||||
|
||||
size_t email_queue_max;
|
||||
size_t max_content_size;
|
||||
} lws_smtp_client_info_t;
|
||||
|
||||
typedef struct lws_smtp_email {
|
||||
struct lws_dll2 list;
|
||||
|
||||
void *data;
|
||||
void *extra;
|
||||
|
||||
time_t added;
|
||||
time_t last_try;
|
||||
|
||||
const char *email_from;
|
||||
const char *email_to;
|
||||
const char *payload;
|
||||
|
||||
int (*done)(struct lws_smtp_email *e, void *buf, size_t len);
|
||||
|
||||
int tries;
|
||||
} lws_smtp_email_t;
|
||||
|
||||
|
||||
/**
|
||||
* lws_smtp_client_create() - Initialize a struct lws_email
|
||||
*
|
||||
* \param abs: abstract transport to use with the new SMTP client
|
||||
* \param ci: parameters describing the new SMTP client characteristics
|
||||
*
|
||||
* Prepares a struct lws_email for use ending SMTP
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN lws_smtp_client_t *
|
||||
lws_smtp_client_create(const lws_smtp_client_info_t *ci);
|
||||
|
||||
/**
|
||||
* lws_smtp_client_alloc_email_helper() - Allocates and inits an email object
|
||||
*
|
||||
* \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
|
||||
*
|
||||
* 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 lws_smtp_email_t *
|
||||
lws_smtp_client_alloc_email_helper(const char *payload, size_t payload_len,
|
||||
const char *sender, const char *recipient,
|
||||
const char *extra, size_t extra_len, void *data,
|
||||
int (*done)(struct lws_smtp_email *e,
|
||||
void *buf, size_t len));
|
||||
|
||||
/**
|
||||
* lws_smtp_client_add_email() - Add email to the list of ones being sent
|
||||
*
|
||||
* \param c: smtp client
|
||||
* \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_smtp_client_add_email(lws_smtp_client_t *c, lws_smtp_email_t *e);
|
||||
|
||||
/**
|
||||
* lws_smtp_client_kick() - Request check for new email
|
||||
*
|
||||
* \param email: lws_smtp_client_t context to kick
|
||||
*
|
||||
* Gives smtp client a chance to move things on
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_smtp_client_kick(lws_smtp_client_t *email);
|
||||
|
||||
/**
|
||||
* lws_smtp_client_destroy() - stop using the struct lws_email
|
||||
*
|
||||
* \param email: the lws_smtp_client_t context
|
||||
*
|
||||
* Stop sending email using email and free allocations
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_smtp_client_destroy(lws_smtp_client_t **email);
|
||||
|
||||
|
||||
#endif
|
||||
//@}
|
31
include/libwebsockets/abstract/transports.h
Normal file
31
include/libwebsockets/abstract/transports.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* included from libwebsockets.h
|
||||
*/
|
||||
|
||||
struct lws_abstract;
|
||||
typedef struct lws_abstract lws_abstract_t;
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_abstract_copy(lws_abstract_t *dest, const lws_abstract_t *src);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN const lws_abstract_t *
|
||||
lws_abstract_get_by_name(const char *name);
|
|
@ -734,6 +734,9 @@ enum lws_callback_reasons {
|
|||
LWS_CALLBACK_RAW_ADOPT = 62,
|
||||
/**< RAW mode connection was adopted (equivalent to 'wsi created') */
|
||||
|
||||
LWS_CALLBACK_RAW_CONNECTED = 101,
|
||||
/**< outgoing client RAW mode connection was connected */
|
||||
|
||||
LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL = 81,
|
||||
LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL = 82,
|
||||
|
||||
|
|
|
@ -886,128 +886,4 @@ lws_get_ssl(struct lws *wsi);
|
|||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_explicit_bzero(void *p, size_t len);
|
||||
|
||||
/** \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.
|
||||
*
|
||||
* It runs via its own libuv events if initialized (which requires giving it
|
||||
* a libuv loop to attach to).
|
||||
*
|
||||
* It operates using three callbacks, on_next() queries if there is a new email
|
||||
* to send, on_get_body() asks for the body of the email, and on_sent() is
|
||||
* called after the email is successfully sent.
|
||||
*
|
||||
* To use it
|
||||
*
|
||||
* - create an lws_email struct
|
||||
*
|
||||
* - initialize data, loop, the email_* strings, max_content_size and
|
||||
* the callbacks
|
||||
*
|
||||
* - call lws_email_init()
|
||||
*
|
||||
* When you have at least one email to send, call lws_email_check() to
|
||||
* schedule starting to send it.
|
||||
*/
|
||||
//@{
|
||||
#ifdef LWS_WITH_SMTP
|
||||
|
||||
/** enum lwsgs_smtp_states - where we are in SMTP protocol sequence */
|
||||
enum lwsgs_smtp_states {
|
||||
LGSSMTP_IDLE, /**< awaiting new email */
|
||||
LGSSMTP_CONNECTING, /**< opening tcp connection to MTA */
|
||||
LGSSMTP_CONNECTED, /**< tcp connection to MTA is connected */
|
||||
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 */
|
||||
LGSSMTP_SENT_QUIT, /**< sent the session quit */
|
||||
};
|
||||
|
||||
/** struct lws_email - abstract context for performing SMTP operations */
|
||||
struct lws_email {
|
||||
void *data;
|
||||
/**< opaque pointer set by user code and available to the callbacks */
|
||||
uv_loop_t *loop;
|
||||
/**< the libuv loop we will work on */
|
||||
|
||||
char email_smtp_ip[32]; /**< Fill before init, eg, "127.0.0.1" */
|
||||
char email_helo[32]; /**< Fill before init, eg, "myserver.com" */
|
||||
char email_from[100]; /**< Fill before init or on_next */
|
||||
char email_to[100]; /**< Fill before init or on_next */
|
||||
|
||||
unsigned int max_content_size;
|
||||
/**< largest possible email body size */
|
||||
|
||||
/* Fill all the callbacks before init */
|
||||
|
||||
int (*on_next)(struct lws_email *email);
|
||||
/**< (Fill in before calling lws_email_init)
|
||||
* called when idle, 0 = another email to send, nonzero is idle.
|
||||
* If you return 0, all of the email_* char arrays must be set
|
||||
* to something useful. */
|
||||
int (*on_sent)(struct lws_email *email);
|
||||
/**< (Fill in before calling lws_email_init)
|
||||
* called when transfer of the email to the SMTP server was
|
||||
* successful, your callback would remove the current email
|
||||
* from its queue */
|
||||
int (*on_get_body)(struct lws_email *email, char *buf, int len);
|
||||
/**< (Fill in before calling lws_email_init)
|
||||
* called when the body part of the queued email is about to be
|
||||
* sent to the SMTP server. */
|
||||
|
||||
|
||||
/* private things */
|
||||
uv_timer_t timeout_email; /**< private */
|
||||
enum lwsgs_smtp_states estate; /**< private */
|
||||
uv_connect_t email_connect_req; /**< private */
|
||||
uv_tcp_t email_client; /**< private */
|
||||
time_t email_connect_started; /**< private */
|
||||
char email_buf[256]; /**< private */
|
||||
char *content; /**< private */
|
||||
};
|
||||
|
||||
/**
|
||||
* lws_email_init() - Initialize a struct lws_email
|
||||
*
|
||||
* \param email: struct lws_email to init
|
||||
* \param loop: libuv loop to use
|
||||
* \param max_content: max email content size
|
||||
*
|
||||
* Prepares a struct lws_email for use ending SMTP
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_email_init(struct lws_email *email, uv_loop_t *loop, int max_content);
|
||||
|
||||
/**
|
||||
* lws_email_check() - Request check for new email
|
||||
*
|
||||
* \param email: struct lws_email context to check
|
||||
*
|
||||
* Schedules a check for new emails in 1s... call this when you have queued an
|
||||
* email for send.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_email_check(struct lws_email *email);
|
||||
/**
|
||||
* lws_email_destroy() - stop using the struct lws_email
|
||||
*
|
||||
* \param email: the struct lws_email context
|
||||
*
|
||||
* Stop sending email using email and free allocations
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_email_destroy(struct lws_email *email);
|
||||
|
||||
#endif
|
||||
//@}
|
||||
|
||||
///@}
|
||||
|
|
52
lib/abstract/abstract.c
Normal file
52
lib/abstract/abstract.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <core/private.h>
|
||||
#include <abstract/private.h>
|
||||
|
||||
extern lws_abstract_t lws_abstract_transport_cli_raw_skt;
|
||||
|
||||
static const lws_abstract_t *available_abstractions[] = {
|
||||
&lws_abstract_transport_cli_raw_skt,
|
||||
};
|
||||
|
||||
/*
|
||||
* the definition is opaque, so a helper to copy it into place
|
||||
*/
|
||||
|
||||
void
|
||||
lws_abstract_copy(lws_abstract_t *dest, const lws_abstract_t *src)
|
||||
{
|
||||
memcpy(dest, src, sizeof(*dest));
|
||||
}
|
||||
|
||||
|
||||
const lws_abstract_t *
|
||||
lws_abstract_get_by_name(const char *name)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(available_abstractions); n++)
|
||||
if (!strcmp(name, available_abstractions[n]->name))
|
||||
return available_abstractions[n];
|
||||
|
||||
return NULL;
|
||||
}
|
68
lib/abstract/private.h
Normal file
68
lib/abstract/private.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
struct lws_abstract;
|
||||
|
||||
typedef void lws_abs_user_t;
|
||||
typedef void lws_abs_t;
|
||||
|
||||
/*
|
||||
* The abstract callbacks are in three parts
|
||||
*
|
||||
* - create and destroy
|
||||
*
|
||||
* - events handled by the transport
|
||||
*
|
||||
* - events handled by the user of the transport
|
||||
*
|
||||
* the canned abstract transports only define the first two types... the
|
||||
* remaining callbacks must be filled in to callback functions specific to
|
||||
* the user of the abstract transport.
|
||||
*/
|
||||
|
||||
typedef struct lws_abstract {
|
||||
|
||||
const char *name;
|
||||
|
||||
lws_abs_user_t * (*create)(struct lws_abstract *abs, void *user);
|
||||
void (*destroy)(lws_abs_user_t **d);
|
||||
|
||||
/* events the abstract object invokes (filled in by transport) */
|
||||
|
||||
int (*tx)(lws_abs_user_t *d, uint8_t *buf, size_t len);
|
||||
int (*client_conn)(lws_abs_user_t *d, struct lws_vhost *vh,
|
||||
const char *ip, uint16_t port, int tls_flags);
|
||||
int (*close)(lws_abs_user_t *d);
|
||||
int (*ask_for_writeable)(lws_abs_user_t *d);
|
||||
int (*set_timeout)(lws_abs_user_t *d, int reason, int secs);
|
||||
int (*state)(lws_abs_user_t *d);
|
||||
|
||||
/* events the transport invokes (filled in by abstract object) */
|
||||
|
||||
int (*accept)(lws_abs_user_t *d);
|
||||
int (*rx)(lws_abs_user_t *d, uint8_t *buf, size_t len);
|
||||
int (*writeable)(lws_abs_user_t *d, size_t budget);
|
||||
int (*closed)(lws_abs_user_t *d);
|
||||
int (*heartbeat)(lws_abs_user_t *d);
|
||||
|
||||
} lws_abstract_t;
|
||||
|
||||
|
51
lib/abstract/smtp/private.h
Normal file
51
lib/abstract/smtp/private.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* libwebsockets lib/abstruct/smtp/private.h
|
||||
*
|
||||
* Copyright (C) 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "abstract/private.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 */
|
||||
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 */
|
||||
LGSSMTP_SENT_QUIT, /**< sent the session quit */
|
||||
} lwsgs_smtp_states_t;
|
||||
|
||||
/** struct lws_email - abstract context for performing SMTP operations */
|
||||
typedef struct lws_smtp_client {
|
||||
struct lws_dll2_owner pending_owner;
|
||||
|
||||
lws_smtp_client_info_t i;
|
||||
lws_abstract_t abs;
|
||||
|
||||
lws_abs_user_t *abs_conn;
|
||||
|
||||
lwsgs_smtp_states_t estate;
|
||||
time_t email_connect_started;
|
||||
|
||||
unsigned char send_pending:1;
|
||||
} lws_smtp_client_t;
|
||||
|
395
lib/abstract/smtp/smtp.c
Normal file
395
lib/abstract/smtp/smtp.c
Normal file
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Abstract SMTP support for libwebsockets
|
||||
*
|
||||
* Copyright (C) 2016-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "core/private.h"
|
||||
#include "abstract/smtp/private.h"
|
||||
|
||||
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_smtp_client_state_transition(lws_smtp_client_t *c, lwsgs_smtp_states_t s)
|
||||
{
|
||||
lwsl_debug("%s: cli %p: state %d -> %d\n", __func__, c, c->estate, s);
|
||||
c->estate = s;
|
||||
}
|
||||
|
||||
void
|
||||
lws_smtp_client_kick(lws_smtp_client_t *c)
|
||||
{
|
||||
lws_smtp_email_t *e;
|
||||
lws_dll2_t *d;
|
||||
char buf[64];
|
||||
int n;
|
||||
|
||||
if (c->estate != LGSSMTP_IDLE)
|
||||
return;
|
||||
|
||||
/* is there something to do? */
|
||||
|
||||
again:
|
||||
d = lws_dll2_get_head(&c->pending_owner);
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
e = lws_container_of(d, lws_smtp_email_t, list);
|
||||
|
||||
/* do we need to time out this guy? */
|
||||
|
||||
if ((time_t)lws_now_secs() - e->added > (time_t)c->i.delivery_timeout) {
|
||||
lwsl_err("%s: timing out email\n", __func__);
|
||||
lws_dll2_remove(&e->list);
|
||||
n = lws_snprintf(buf, sizeof(buf), "0 Timed out retrying send");
|
||||
e->done(e, buf, n);
|
||||
|
||||
if (lws_dll2_get_head(&c->pending_owner))
|
||||
goto again;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* is it time for his retry yet? */
|
||||
|
||||
if (e->last_try &&
|
||||
(time_t)lws_now_secs() - e->last_try < (time_t)c->i.retry_interval) {
|
||||
/* no... send him to the tail */
|
||||
lws_dll2_remove(&e->list);
|
||||
lws_dll2_add_tail(&e->list, &c->pending_owner);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if we have a connection to the server ongoing */
|
||||
|
||||
if (c->abs.state(c->abs_conn)) {
|
||||
/*
|
||||
* there's a connection, it could be still trying to connect
|
||||
* or established
|
||||
*/
|
||||
c->abs.ask_for_writeable(c->abs_conn);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* there's no existing connection */
|
||||
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_CONNECTING);
|
||||
lwsl_notice("LGSSMTP_IDLE: connecting to %s:25\n", c->i.ip);
|
||||
|
||||
if (c->abs.client_conn(c->abs_conn, c->i.vh, c->i.ip, 25, 0)) {
|
||||
lwsl_err("%s: failed to connect to %s:25\n",
|
||||
__func__, c->i.ip);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
e->tries++;
|
||||
e->last_try = lws_now_secs();
|
||||
}
|
||||
|
||||
/*
|
||||
* we became connected
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_smtp_client_abs_accept(lws_abs_user_t *abs_priv)
|
||||
{
|
||||
lws_smtp_client_t *c = (lws_smtp_client_t *)abs_priv;
|
||||
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_CONNECTED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtp_client_abs_rx(lws_abs_user_t *abs_priv, uint8_t *buf, size_t len)
|
||||
{
|
||||
lws_smtp_client_t *c = (lws_smtp_client_t *)abs_priv;
|
||||
lws_smtp_email_t *e;
|
||||
lws_dll2_t *pd2;
|
||||
int n;
|
||||
|
||||
pd2 = lws_dll2_get_head(&c->pending_owner);
|
||||
if (!pd2)
|
||||
return 0;
|
||||
|
||||
e = lws_container_of(pd2, lws_smtp_email_t, list);
|
||||
if (!e)
|
||||
return 0;
|
||||
|
||||
lwsl_debug("%s: rx: '%.*s'\n", __func__, (int)len, (const char *)buf);
|
||||
|
||||
n = atoi((char *)buf);
|
||||
if (n != retcodes[c->estate]) {
|
||||
lwsl_notice("%s: bad response from server: %d (state %d) %.*s\n",
|
||||
__func__, n, c->estate, (int)len, buf);
|
||||
|
||||
lws_dll2_remove(&e->list);
|
||||
lws_dll2_add_tail(&e->list, &c->pending_owner);
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_IDLE);
|
||||
lws_smtp_client_kick(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c->estate == LGSSMTP_SENT_QUIT) {
|
||||
lwsl_debug("%s: done\n", __func__);
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_IDLE);
|
||||
|
||||
lws_dll2_remove(&e->list);
|
||||
if (e->done && e->done(e, "sent OK", 7))
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
c->send_pending = 1;
|
||||
c->abs.ask_for_writeable(c->abs_conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtp_client_abs_writeable(lws_abs_user_t *abs_priv, size_t budget)
|
||||
{
|
||||
lws_smtp_client_t *c = (lws_smtp_client_t *)abs_priv;
|
||||
char b[256 + LWS_PRE], *p = b + LWS_PRE;
|
||||
lws_smtp_email_t *e;
|
||||
lws_dll2_t *pd2;
|
||||
int n;
|
||||
|
||||
pd2 = lws_dll2_get_head(&c->pending_owner);
|
||||
if (!pd2)
|
||||
return 0;
|
||||
|
||||
e = lws_container_of(pd2, lws_smtp_email_t, list);
|
||||
if (!e)
|
||||
return 0;
|
||||
|
||||
|
||||
if (!c->send_pending)
|
||||
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->i.helo);
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_SENT_HELO);
|
||||
break;
|
||||
case LGSSMTP_SENT_HELO:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE, "MAIL FROM: <%s>\n",
|
||||
e->email_from);
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_SENT_FROM);
|
||||
break;
|
||||
case LGSSMTP_SENT_FROM:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE,
|
||||
"RCPT TO: <%s>\n", e->email_to);
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_SENT_TO);
|
||||
break;
|
||||
case LGSSMTP_SENT_TO:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE, "DATA\n");
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_SENT_DATA);
|
||||
break;
|
||||
case LGSSMTP_SENT_DATA:
|
||||
p = (char *)e->payload;
|
||||
n = strlen(e->payload);
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_SENT_BODY);
|
||||
break;
|
||||
case LGSSMTP_SENT_BODY:
|
||||
n = lws_snprintf(p, sizeof(b) - LWS_PRE, "quit\n");
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_SENT_QUIT);
|
||||
break;
|
||||
case LGSSMTP_SENT_QUIT:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
//puts(p);
|
||||
c->abs.tx(c->abs_conn, (uint8_t *)p, n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtp_client_abs_closed(lws_abs_user_t *abs_priv)
|
||||
{
|
||||
lws_smtp_client_t *c = (lws_smtp_client_t *)abs_priv;
|
||||
|
||||
c->abs_conn = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_smtp_client_abs_heartbeat(lws_abs_user_t *abs_priv)
|
||||
{
|
||||
lws_smtp_client_t *c = (lws_smtp_client_t *)abs_priv;
|
||||
|
||||
lws_smtp_client_kick(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_smtp_email_t *
|
||||
lws_smtp_client_alloc_email_helper(const char *payload, size_t payload_len,
|
||||
const char *sender, const char *recipient,
|
||||
const char *extra, size_t extra_len, void *data,
|
||||
int (*done)(struct lws_smtp_email *e,
|
||||
void *buf, size_t len))
|
||||
{
|
||||
size_t ls = strlen(sender), lr = strlen(recipient);
|
||||
lws_smtp_email_t *em;
|
||||
char *p;
|
||||
|
||||
em = malloc(sizeof(*em) + payload_len + ls + lr + extra_len + 4);
|
||||
if (!em) {
|
||||
lwsl_err("OOM\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = (char *)&em[1];
|
||||
|
||||
memset(em, 0, sizeof(*em));
|
||||
|
||||
em->data = data;
|
||||
em->done = done;
|
||||
|
||||
em->email_from = p;
|
||||
memcpy(p, sender, ls + 1);
|
||||
p += ls + 1;
|
||||
em->email_to = p;
|
||||
memcpy(p, recipient, lr + 1);
|
||||
p += lr + 1;
|
||||
em->payload = p;
|
||||
memcpy(p, payload, payload_len + 1);
|
||||
p += payload_len + 1;
|
||||
|
||||
if (extra) {
|
||||
em->extra = p;
|
||||
memcpy(p, extra, extra_len + 1);
|
||||
}
|
||||
|
||||
return em;
|
||||
}
|
||||
|
||||
int
|
||||
lws_smtp_client_add_email(lws_smtp_client_t *c, lws_smtp_email_t *e)
|
||||
{
|
||||
if (c->pending_owner.count > c->i.email_queue_max) {
|
||||
lwsl_err("%s: email queue at limit of %d\n", __func__,
|
||||
(int)c->i.email_queue_max);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
e->added = lws_now_secs();
|
||||
e->last_try = 0;
|
||||
e->tries = 0;
|
||||
|
||||
lws_dll2_clear(&e->list);
|
||||
lws_dll2_add_tail(&e->list, &c->pending_owner);
|
||||
|
||||
lws_smtp_client_kick(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_smtp_client_t *
|
||||
lws_smtp_client_create(const lws_smtp_client_info_t *ci)
|
||||
{
|
||||
lws_smtp_client_t *c;
|
||||
|
||||
c = lws_zalloc(sizeof(*c), "email client");
|
||||
if (!c)
|
||||
return NULL;
|
||||
|
||||
c->i = *ci;
|
||||
c->abs = *ci->abs;
|
||||
|
||||
/* fill in the additional abstract callbacks we fulfil */
|
||||
|
||||
c->abs.accept = lws_smtp_client_abs_accept;
|
||||
c->abs.rx = lws_smtp_client_abs_rx;
|
||||
c->abs.writeable = lws_smtp_client_abs_writeable;
|
||||
c->abs.closed = lws_smtp_client_abs_closed;
|
||||
c->abs.heartbeat = lws_smtp_client_abs_heartbeat;
|
||||
|
||||
if (!c->i.email_queue_max)
|
||||
c->i.email_queue_max = 8;
|
||||
|
||||
if (!c->i.retry_interval)
|
||||
c->i.retry_interval = 15 * 60;
|
||||
|
||||
if (!c->i.delivery_timeout)
|
||||
c->i.delivery_timeout = 12 * 60 * 60;
|
||||
|
||||
c->abs_conn = c->abs.create(&c->abs, c);
|
||||
if (!c->abs_conn) {
|
||||
lws_free(c);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lws_smtp_client_state_transition(c, LGSSMTP_IDLE);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
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))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_smtp_client_destroy(lws_smtp_client_t **c)
|
||||
{
|
||||
if (!*c)
|
||||
return;
|
||||
|
||||
lws_dll2_foreach_safe(&(*c)->pending_owner, NULL, cleanup);
|
||||
|
||||
if ((*c)->abs_conn) {
|
||||
(*c)->abs.close((*c)->abs_conn);
|
||||
(*c)->abs.destroy(&(*c)->abs_conn);
|
||||
}
|
||||
|
||||
lws_free_set_NULL(*c);
|
||||
}
|
309
lib/abstract/transports/raw-skt.c
Normal file
309
lib/abstract/transports/raw-skt.c
Normal file
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* libwebsockets lib/abstruct/transports/raw-skt.c
|
||||
*
|
||||
* Copyright (C) 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "core/private.h"
|
||||
#include "abstract/private.h"
|
||||
|
||||
typedef struct lws_atrs_priv {
|
||||
struct lws_abstract *abs;
|
||||
struct lws *wsi;
|
||||
void *user;
|
||||
|
||||
lws_dll2_t same_abs_transport_list;
|
||||
|
||||
uint8_t established:1;
|
||||
uint8_t connecting:1;
|
||||
} lws_atrs_priv_t;
|
||||
|
||||
struct vhd {
|
||||
lws_dll2_owner_t owner;
|
||||
};
|
||||
|
||||
static int
|
||||
heartbeat_cb(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_atrs_priv_t *priv = lws_container_of(d, lws_atrs_priv_t,
|
||||
same_abs_transport_list);
|
||||
if (priv->abs->heartbeat)
|
||||
priv->abs->heartbeat(priv->user);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
callback_abs_client_raw_skt(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
lws_atrs_priv_t *priv = (lws_atrs_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->accept)
|
||||
priv->abs->accept(priv->user);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
lwsl_user("CONNECTION_ERROR\n");
|
||||
if (in)
|
||||
lwsl_user(" %s\n", (const char *)in);
|
||||
|
||||
/* fallthru */
|
||||
case LWS_CALLBACK_RAW_CLOSE:
|
||||
if (!user)
|
||||
break;
|
||||
lwsl_debug("LWS_CALLBACK_RAW_CLOSE\n");
|
||||
priv->established = 0;
|
||||
priv->connecting = 0;
|
||||
if (priv->abs && priv->abs->closed)
|
||||
priv->abs->closed(priv->user);
|
||||
lws_free(priv);
|
||||
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->rx(priv->user, in, len);
|
||||
|
||||
case LWS_CALLBACK_RAW_WRITEABLE:
|
||||
lwsl_debug("LWS_CALLBACK_RAW_WRITEABLE\n");
|
||||
priv->abs->writeable(priv->user,
|
||||
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;
|
||||
}
|
||||
|
||||
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_user_t *abs_priv, uint8_t *buf, size_t len)
|
||||
{
|
||||
lws_atrs_priv_t *priv = (lws_atrs_priv_t *)abs_priv;
|
||||
|
||||
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)
|
||||
priv->abs->close(priv->user);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(LWS_WITHOUT_CLIENT)
|
||||
static int
|
||||
lws_atcrs_client_conn(lws_abs_user_t *abs_priv, struct lws_vhost *vh,
|
||||
const char *ip, uint16_t port, int tls_flags)
|
||||
{
|
||||
lws_atrs_priv_t *priv = (lws_atrs_priv_t *)abs_priv;
|
||||
struct lws_client_connect_info i;
|
||||
|
||||
if (priv->connecting)
|
||||
return 0;
|
||||
|
||||
if (priv->established) {
|
||||
lws_set_timeout(priv->wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: priv %p connecting to %s:%u %p\n", __func__, priv,
|
||||
ip, port, vh->context);
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
|
||||
i.path = "";
|
||||
i.vhost = vh;
|
||||
i.port = port;
|
||||
i.address = ip;
|
||||
i.method = "RAW";
|
||||
i.userdata = priv;
|
||||
i.host = i.address;
|
||||
i.pwsi = &priv->wsi;
|
||||
i.origin = i.address;
|
||||
i.context = vh->context;
|
||||
i.ssl_connection = tls_flags;
|
||||
i.local_protocol_name = "lws-abs-cli-raw-skt";
|
||||
|
||||
priv->wsi = lws_client_connect_via_info(&i);
|
||||
if (!priv->wsi)
|
||||
return 1;
|
||||
|
||||
priv->connecting = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
lws_atcrs_close(lws_abs_user_t *abs_priv)
|
||||
{
|
||||
lws_atrs_priv_t *priv = (lws_atrs_priv_t *)abs_priv;
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcrs_ask_for_writeable(lws_abs_user_t *abs_priv)
|
||||
{
|
||||
lws_atrs_priv_t *priv = (lws_atrs_priv_t *)abs_priv;
|
||||
|
||||
if (!priv->wsi || !priv->established)
|
||||
return 1;
|
||||
|
||||
lws_callback_on_writable(priv->wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lws_abs_user_t *
|
||||
lws_atcrs_create(struct lws_abstract *abs, void *user)
|
||||
{
|
||||
lws_atrs_priv_t *p = lws_zalloc(sizeof(*p), __func__);
|
||||
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
lwsl_debug("%s: created priv %p\n", __func__, p);
|
||||
|
||||
p->abs = abs;
|
||||
p->user = user;
|
||||
|
||||
return (lws_abs_user_t *)p;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_atcrs_destroy(lws_abs_user_t **abs_priv)
|
||||
{
|
||||
lws_free_set_NULL(*abs_priv);
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcrs_set_timeout(lws_abs_user_t *d, int reason, int secs)
|
||||
{
|
||||
lws_atrs_priv_t *priv = (lws_atrs_priv_t *)d;
|
||||
|
||||
lws_set_timeout(priv->wsi, reason, secs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_atcrs_state(lws_abs_user_t *abs_priv)
|
||||
{
|
||||
lws_atrs_priv_t *priv = (lws_atrs_priv_t *)abs_priv;
|
||||
|
||||
if (!priv || !priv->wsi || (!priv->established && !priv->connecting))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
lws_abstract_t lws_abstract_transport_cli_raw_skt = {
|
||||
"raw-skt",
|
||||
lws_atcrs_create,
|
||||
lws_atcrs_destroy,
|
||||
|
||||
lws_atcrs_tx,
|
||||
#if defined(LWS_WITHOUT_CLIENT)
|
||||
NULL,
|
||||
#else
|
||||
lws_atcrs_client_conn,
|
||||
#endif
|
||||
lws_atcrs_close,
|
||||
lws_atcrs_ask_for_writeable,
|
||||
lws_atcrs_set_timeout,
|
||||
lws_atcrs_state,
|
||||
|
||||
/*
|
||||
* remaining callbacks must be defined by abstract object and are
|
||||
* called by this protocol handler
|
||||
*/
|
||||
|
||||
NULL, /* accept */
|
||||
NULL, /* rx */
|
||||
NULL, /* writeable */
|
||||
NULL /* closed */
|
||||
};
|
|
@ -60,6 +60,7 @@ lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
new_wsi->wsistate |= LWSIFR_SERVER;
|
||||
new_wsi->tsi = n;
|
||||
lwsl_debug("new wsi %p joining vhost %s, tsi %d\n", new_wsi,
|
||||
vhost->name, new_wsi->tsi);
|
||||
|
@ -208,11 +209,12 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
* selected yet so we issue this to the vhosts's default protocol,
|
||||
* itself by default protocols[0]
|
||||
*/
|
||||
new_wsi->wsistate |= LWSIFR_SERVER;
|
||||
n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
|
||||
if (new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)])
|
||||
n = new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)];
|
||||
|
||||
lwsl_debug("new wsi wsistate 0x%x\n", new_wsi->wsistate);
|
||||
lwsl_err("new wsi wsistate 0x%x\n", new_wsi->wsistate);
|
||||
|
||||
if (context->event_loop_ops->accept)
|
||||
if (context->event_loop_ops->accept(new_wsi))
|
||||
|
|
|
@ -1070,6 +1070,8 @@ int
|
|||
lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
|
||||
int buffered);
|
||||
|
||||
extern const struct lws_protocols protocol_abs_client_raw_skt;
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -56,6 +56,13 @@ const struct lws_event_loop_ops *available_event_libs[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
const struct lws_protocols *available_abstract_protocols[] = {
|
||||
#if defined(LWS_ROLE_RAW)
|
||||
&protocol_abs_client_raw_skt,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char * const mount_protocols[] = {
|
||||
"http://",
|
||||
"https://",
|
||||
|
@ -420,12 +427,11 @@ lws_create_vhost(struct lws_context *context,
|
|||
**vh1 = &context->vhost_list;
|
||||
const struct lws_http_mount *mounts;
|
||||
const struct lws_protocols *pcols = info->protocols;
|
||||
const struct lws_protocol_vhost_options *pvo;
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
struct lws_plugin *plugin = context->plugin_list;
|
||||
#endif
|
||||
struct lws_protocols *lwsp;
|
||||
int m, f = !info->pvo, fx = 0;
|
||||
int m, f = !info->pvo, fx = 0, abs_pcol_count;
|
||||
char buf[20];
|
||||
#if !defined(LWS_WITHOUT_CLIENT) && defined(LWS_HAVE_GETENV)
|
||||
char *p;
|
||||
|
@ -539,18 +545,30 @@ lws_create_vhost(struct lws_context *context,
|
|||
fx = 1;
|
||||
#endif
|
||||
|
||||
abs_pcol_count = (int)LWS_ARRAY_SIZE(available_abstract_protocols) - 1;
|
||||
|
||||
/*
|
||||
* give the vhost a unified list of protocols including the
|
||||
* ones that came from plugins
|
||||
* give the vhost a unified list of protocols including:
|
||||
*
|
||||
* - internal, abstracted ones
|
||||
* - the ones that came from plugins
|
||||
* - his user protocols
|
||||
*/
|
||||
lwsp = lws_zalloc(sizeof(struct lws_protocols) * (vh->count_protocols +
|
||||
context->plugin_protocol_count + fx + 1),
|
||||
lwsp = lws_zalloc(sizeof(struct lws_protocols) *
|
||||
(vh->count_protocols +
|
||||
abs_pcol_count +
|
||||
context->plugin_protocol_count +
|
||||
fx + 1),
|
||||
"vhost-specific plugin table");
|
||||
if (!lwsp) {
|
||||
lwsl_err("OOM\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1: user protocols (from pprotocols or protocols)
|
||||
*/
|
||||
|
||||
m = vh->count_protocols;
|
||||
if (!pcols) {
|
||||
for (n = 0; n < m; n++)
|
||||
|
@ -559,7 +577,17 @@ lws_create_vhost(struct lws_context *context,
|
|||
memcpy(lwsp, pcols, sizeof(struct lws_protocols) * m);
|
||||
|
||||
/*
|
||||
* For compatibility, all protocols enabled on vhost if only
|
||||
* 2: abstract protocols
|
||||
*/
|
||||
|
||||
for (n = 0; n < abs_pcol_count; n++) {
|
||||
memcpy(&lwsp[m++], available_abstract_protocols[n],
|
||||
sizeof(*lwsp));
|
||||
vh->count_protocols++;
|
||||
}
|
||||
|
||||
/*
|
||||
* 3: For compatibility, all protocols enabled on vhost if only
|
||||
* the default vhost exists. Otherwise only vhosts who ask
|
||||
* for a protocol get it enabled.
|
||||
*/
|
||||
|
@ -569,7 +597,6 @@ lws_create_vhost(struct lws_context *context,
|
|||
(void)f;
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (plugin) {
|
||||
|
||||
while (plugin) {
|
||||
for (n = 0; n < plugin->caps.count_protocols; n++) {
|
||||
/*
|
||||
|
@ -591,21 +618,12 @@ lws_create_vhost(struct lws_context *context,
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
|
||||
memcpy(&lwsp[m++], &lws_ws_proxy, sizeof(lws_ws_proxy));
|
||||
memcpy(&lwsp[m++], &lws_ws_proxy, sizeof(*lwsp));
|
||||
vh->count_protocols++;
|
||||
#endif
|
||||
|
||||
if (!pcols ||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
(context->plugin_list) ||
|
||||
#endif
|
||||
(context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
|
||||
vh->protocols = lwsp;
|
||||
vh->allocated_vhost_protocols = 1;
|
||||
} else {
|
||||
vh->protocols = pcols;
|
||||
lws_free(lwsp);
|
||||
}
|
||||
vh->protocols = lwsp;
|
||||
vh->allocated_vhost_protocols = 1;
|
||||
|
||||
vh->same_vh_protocol_heads = (struct lws_dll *)
|
||||
lws_zalloc(sizeof(struct lws_dll) *
|
||||
|
@ -643,22 +661,6 @@ lws_create_vhost(struct lws_context *context,
|
|||
mount_protocols[mounts->origin_protocol],
|
||||
mounts->origin, mounts->mountpoint);
|
||||
|
||||
/* convert interpreter protocol names to pointers */
|
||||
pvo = mounts->interpret;
|
||||
while (pvo) {
|
||||
for (n = 0; n < vh->count_protocols; n++) {
|
||||
if (strcmp(pvo->value, vh->protocols[n].name))
|
||||
continue;
|
||||
((struct lws_protocol_vhost_options *)pvo)->
|
||||
value = (const char *)(lws_intptr_t)n;
|
||||
break;
|
||||
}
|
||||
if (n == vh->count_protocols)
|
||||
lwsl_err("ignoring unknown interp pr %s\n",
|
||||
pvo->value);
|
||||
pvo = pvo->next;
|
||||
}
|
||||
|
||||
mounts = mounts->mount_next;
|
||||
}
|
||||
|
||||
|
|
242
lib/misc/smtp.c
242
lib/misc/smtp.c
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
* SMTP support for libwebsockets
|
||||
*
|
||||
* Copyright (C) 2016-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "core/private.h"
|
||||
|
||||
static unsigned int
|
||||
lwsgs_now_secs(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
return tv.tv_sec;
|
||||
}
|
||||
|
||||
static void
|
||||
ccb(uv_handle_t* handle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
|
||||
{
|
||||
struct lws_email *email = (struct lws_email *)handle->data;
|
||||
|
||||
*buf = uv_buf_init(email->email_buf, sizeof(email->email_buf) - 1);
|
||||
}
|
||||
|
||||
static void
|
||||
on_write_end(uv_write_t *req, int status) {
|
||||
lwsl_notice("%s\n", __func__);
|
||||
if (status == -1) {
|
||||
fprintf(stderr, "error on_write_end");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)
|
||||
{
|
||||
struct lws_email *email = (struct lws_email *)s->data;
|
||||
static const short retcodes[] = {
|
||||
0, /* idle */
|
||||
0, /* connecting */
|
||||
220, /* connected */
|
||||
250, /* helo */
|
||||
250, /* from */
|
||||
250, /* to */
|
||||
354, /* data */
|
||||
250, /* body */
|
||||
221, /* quit */
|
||||
};
|
||||
uv_write_t write_req;
|
||||
uv_buf_t wbuf;
|
||||
int n;
|
||||
|
||||
if (nread >= 0)
|
||||
email->email_buf[nread] = '\0';
|
||||
lwsl_notice("%s: %s\n", __func__, buf->base);
|
||||
if (nread == -1) {
|
||||
lwsl_err("%s: failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
n = atoi(buf->base);
|
||||
if (n != retcodes[email->estate]) {
|
||||
lwsl_err("%s: bad response from server\n", __func__);
|
||||
goto close_conn;
|
||||
}
|
||||
|
||||
switch (email->estate) {
|
||||
case LGSSMTP_CONNECTED:
|
||||
n = sprintf(email->content, "HELO %s\n", email->email_helo);
|
||||
email->estate = LGSSMTP_SENT_HELO;
|
||||
break;
|
||||
case LGSSMTP_SENT_HELO:
|
||||
n = sprintf(email->content, "MAIL FROM: <%s>\n",
|
||||
email->email_from);
|
||||
email->estate = LGSSMTP_SENT_FROM;
|
||||
break;
|
||||
case LGSSMTP_SENT_FROM:
|
||||
n = sprintf(email->content, "RCPT TO: <%s>\n", email->email_to);
|
||||
email->estate = LGSSMTP_SENT_TO;
|
||||
break;
|
||||
case LGSSMTP_SENT_TO:
|
||||
n = sprintf(email->content, "DATA\n");
|
||||
email->estate = LGSSMTP_SENT_DATA;
|
||||
break;
|
||||
case LGSSMTP_SENT_DATA:
|
||||
if (email->on_get_body(email, email->content,
|
||||
email->max_content_size))
|
||||
return;
|
||||
n = strlen(email->content);
|
||||
email->estate = LGSSMTP_SENT_BODY;
|
||||
break;
|
||||
case LGSSMTP_SENT_BODY:
|
||||
n = sprintf(email->content, "quit\n");
|
||||
email->estate = LGSSMTP_SENT_QUIT;
|
||||
break;
|
||||
case LGSSMTP_SENT_QUIT:
|
||||
lwsl_notice("%s: done\n", __func__);
|
||||
email->on_sent(email);
|
||||
email->estate = LGSSMTP_IDLE;
|
||||
goto close_conn;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
puts(email->content);
|
||||
wbuf = uv_buf_init(email->content, n);
|
||||
uv_write(&write_req, s, &wbuf, 1, on_write_end);
|
||||
|
||||
return;
|
||||
|
||||
close_conn:
|
||||
|
||||
uv_close((uv_handle_t *)s, ccb);
|
||||
}
|
||||
|
||||
static void
|
||||
lwsgs_email_on_connect(uv_connect_t *req, int status)
|
||||
{
|
||||
struct lws_email *email = (struct lws_email *)req->data;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
if (status == -1) {
|
||||
lwsl_err("%s: failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
uv_read_start(req->handle, alloc_buffer, lwsgs_email_read);
|
||||
email->estate = LGSSMTP_CONNECTED;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
uv_timeout_cb_email(uv_timer_t *w
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct lws_email *email = lws_container_of(w, struct lws_email,
|
||||
timeout_email);
|
||||
time_t now = lwsgs_now_secs();
|
||||
struct sockaddr_in req_addr;
|
||||
|
||||
switch (email->estate) {
|
||||
case LGSSMTP_IDLE:
|
||||
|
||||
if (email->on_next(email))
|
||||
break;
|
||||
|
||||
email->estate = LGSSMTP_CONNECTING;
|
||||
|
||||
uv_tcp_init(email->loop, &email->email_client);
|
||||
if (uv_ip4_addr(email->email_smtp_ip, 25, &req_addr)) {
|
||||
lwsl_err("Unable to convert mailserver ads\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lwsl_notice("LGSSMTP_IDLE: connecting\n");
|
||||
|
||||
email->email_connect_started = now;
|
||||
email->email_connect_req.data = email;
|
||||
email->email_client.data = email;
|
||||
uv_tcp_connect(&email->email_connect_req, &email->email_client,
|
||||
(struct sockaddr *)&req_addr,
|
||||
lwsgs_email_on_connect);
|
||||
|
||||
uv_timer_start(&email->timeout_email,
|
||||
uv_timeout_cb_email, 5000, 0);
|
||||
|
||||
break;
|
||||
|
||||
case LGSSMTP_CONNECTING:
|
||||
if (email->email_connect_started - now > 5) {
|
||||
lwsl_err("mail session timed out\n");
|
||||
/* !!! kill the connection */
|
||||
uv_close((uv_handle_t *) &email->email_connect_req, ccb);
|
||||
email->estate = LGSSMTP_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_email_init(struct lws_email *email, uv_loop_t *loop, int max_content)
|
||||
{
|
||||
email->content = lws_malloc(max_content, "email content");
|
||||
if (!email->content)
|
||||
return 1;
|
||||
|
||||
email->max_content_size = max_content;
|
||||
uv_timer_init(loop, &email->timeout_email);
|
||||
|
||||
email->loop = loop;
|
||||
|
||||
/* trigger him one time in a bit */
|
||||
uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 2000, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_email_check(struct lws_email *email)
|
||||
{
|
||||
uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 1000, 0);
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_email_destroy(struct lws_email *email)
|
||||
{
|
||||
if (email->content)
|
||||
lws_free_set_NULL(email->content);
|
||||
|
||||
uv_timer_stop(&email->timeout_email);
|
||||
uv_close((uv_handle_t *)&email->timeout_email, NULL);
|
||||
}
|
|
@ -25,14 +25,195 @@ lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)
|
|||
return getaddrinfo(ads, NULL, &hints, result);
|
||||
}
|
||||
|
||||
|
||||
struct lws *
|
||||
lws_client_connect_3(struct lws *wsi, struct lws *wsi_piggyback, ssize_t plen)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
const char *meth = NULL;
|
||||
struct lws_pollfd pfd;
|
||||
const char *cce = "";
|
||||
int n, m, rawish = 0;
|
||||
|
||||
if (wsi->stash)
|
||||
meth = wsi->stash->method;
|
||||
else
|
||||
meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
|
||||
|
||||
if (meth && !strcmp(meth, "RAW"))
|
||||
rawish = 1;
|
||||
|
||||
if (wsi_piggyback)
|
||||
goto send_hs;
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
/* we are connected to server, or proxy */
|
||||
|
||||
/* http proxy */
|
||||
if (wsi->vhost->http.http_proxy_port) {
|
||||
|
||||
/*
|
||||
* OK from now on we talk via the proxy, so connect to that
|
||||
*
|
||||
* (will overwrite existing pointer,
|
||||
* leaving old string/frag there but unreferenced)
|
||||
*/
|
||||
if (wsi->stash) {
|
||||
lws_free(wsi->stash->address);
|
||||
wsi->stash->address =
|
||||
lws_strdup(wsi->vhost->http.http_proxy_address);
|
||||
if (!wsi->stash->address)
|
||||
goto failed;
|
||||
} else
|
||||
if (lws_hdr_simple_create(wsi,
|
||||
_WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
wsi->vhost->http.http_proxy_address))
|
||||
goto failed;
|
||||
wsi->c_port = wsi->vhost->http.http_proxy_port;
|
||||
|
||||
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, (int)plen,
|
||||
MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing to proxy socket\n");
|
||||
cce = "proxy write failed";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);
|
||||
|
||||
return wsi;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
/* socks proxy */
|
||||
else if (wsi->vhost->socks_proxy_port) {
|
||||
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
|
||||
MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing socks greeting\n");
|
||||
cce = "socks write failed";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY);
|
||||
|
||||
return wsi;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
send_hs:
|
||||
|
||||
if (wsi_piggyback &&
|
||||
!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
|
||||
/*
|
||||
* We are pipelining on an already-established connection...
|
||||
* we can skip tls establishment.
|
||||
*/
|
||||
|
||||
lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
|
||||
|
||||
/*
|
||||
* we can't send our headers directly, because they have to
|
||||
* be sent when the parent is writeable. The parent will check
|
||||
* for anybody on his client transaction queue that is in
|
||||
* LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
|
||||
*
|
||||
* If we are trying to do this too early, before the master
|
||||
* connection has written his own headers, then it will just
|
||||
* wait in the queue until it's possible to send them.
|
||||
*/
|
||||
lws_callback_on_writable(wsi_piggyback);
|
||||
lwsl_info("%s: wsi %p: waiting to send hdrs (par state 0x%x)\n",
|
||||
__func__, wsi, lwsi_state(wsi_piggyback));
|
||||
} else {
|
||||
lwsl_info("%s: wsi %p: %s %s client created own conn (raw %d)\n",
|
||||
__func__, wsi, wsi->role_ops->name,
|
||||
wsi->protocol->name, rawish);
|
||||
|
||||
/* we are making our own connection */
|
||||
if (!rawish)
|
||||
lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);
|
||||
else {
|
||||
/* for a method = "RAW" connection, this makes us
|
||||
* established */
|
||||
|
||||
/* clear his established timeout */
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
m = wsi->role_ops->adoption_cb[0];
|
||||
if (m) {
|
||||
n = user_callback_handle_rxflow(
|
||||
wsi->protocol->callback, wsi,
|
||||
m, wsi->user_space, NULL, 0);
|
||||
if (n < 0) {
|
||||
lwsl_info("LWS_CALLBACK_RAW_PROXY_CLI_ADOPT failed\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* service.c pollout processing wants this */
|
||||
wsi->hdr_parsing_completed = 1;
|
||||
lwsl_info("%s: setting ESTABLISHED\n", __func__);
|
||||
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
/*
|
||||
* provoke service to issue the handshake directly.
|
||||
*
|
||||
* we need to do it this way because in the proxy case, this is
|
||||
* the next state and executed only if and when we get a good
|
||||
* proxy response inside the state machine... but notice in
|
||||
* SSL case this may not have sent anything yet with 0 return,
|
||||
* and won't until many retries from main loop. To stop that
|
||||
* becoming endless, cover with a timeout.
|
||||
*/
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
assert(lws_socket_is_valid(wsi->desc.sockfd));
|
||||
|
||||
pfd.fd = wsi->desc.sockfd;
|
||||
pfd.events = LWS_POLLIN;
|
||||
pfd.revents = LWS_POLLIN;
|
||||
|
||||
n = lws_service_fd(wsi->context, &pfd);
|
||||
if (n < 0) {
|
||||
cce = "first service failed";
|
||||
goto failed;
|
||||
}
|
||||
if (n) /* returns 1 on failure after closing wsi */
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return wsi;
|
||||
|
||||
failed:
|
||||
wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
|
||||
wsi->user_space, (void *)cce, strlen(cce));
|
||||
wsi->already_did_cce = 1;
|
||||
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lws *
|
||||
lws_client_connect_2(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws *wsi_piggyback = NULL;
|
||||
struct lws_pollfd pfd;
|
||||
const char *adsin;
|
||||
ssize_t plen = 0;
|
||||
#endif
|
||||
|
@ -40,7 +221,7 @@ lws_client_connect_2(struct lws *wsi)
|
|||
struct sockaddr_un sau;
|
||||
char unix_skt = 0;
|
||||
#endif
|
||||
int n, m, port = 0, rawish = 0;
|
||||
int n, port = 0;
|
||||
const char *cce = "", *iface;
|
||||
const struct sockaddr *psa;
|
||||
const char *meth = NULL;
|
||||
|
@ -72,9 +253,6 @@ lws_client_connect_2(struct lws *wsi)
|
|||
else
|
||||
meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
|
||||
|
||||
if (meth && !strcmp(meth, "RAW"))
|
||||
rawish = 1;
|
||||
|
||||
if (meth && strcmp(meth, "GET") && strcmp(meth, "POST"))
|
||||
goto create_new_conn;
|
||||
|
||||
|
@ -151,11 +329,8 @@ lws_client_connect_2(struct lws *wsi)
|
|||
* and wait for our turn at client transaction_complete
|
||||
* to take over parsing the rx.
|
||||
*/
|
||||
|
||||
wsi_piggyback = w;
|
||||
|
||||
lws_vhost_unlock(wsi->vhost); /* } ---------- */
|
||||
goto send_hs;
|
||||
return lws_client_connect_3(wsi, w, plen);
|
||||
}
|
||||
|
||||
} lws_end_foreach_dll_safe(d, d1);
|
||||
|
@ -543,157 +718,10 @@ ads_known:
|
|||
}
|
||||
}
|
||||
|
||||
lwsl_client("connected\n");
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
/* we are connected to server, or proxy */
|
||||
|
||||
/* http proxy */
|
||||
if (wsi->vhost->http.http_proxy_port) {
|
||||
return lws_client_connect_3(wsi, NULL, plen);
|
||||
|
||||
/*
|
||||
* OK from now on we talk via the proxy, so connect to that
|
||||
*
|
||||
* (will overwrite existing pointer,
|
||||
* leaving old string/frag there but unreferenced)
|
||||
*/
|
||||
if (wsi->stash) {
|
||||
lws_free(wsi->stash->address);
|
||||
wsi->stash->address =
|
||||
lws_strdup(wsi->vhost->http.http_proxy_address);
|
||||
if (!wsi->stash->address)
|
||||
goto failed;
|
||||
} else
|
||||
if (lws_hdr_simple_create(wsi,
|
||||
_WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
wsi->vhost->http.http_proxy_address))
|
||||
goto failed;
|
||||
wsi->c_port = wsi->vhost->http.http_proxy_port;
|
||||
|
||||
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, (int)plen,
|
||||
MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing to proxy socket\n");
|
||||
cce = "proxy write failed";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);
|
||||
|
||||
return wsi;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
/* socks proxy */
|
||||
else if (wsi->vhost->socks_proxy_port) {
|
||||
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
|
||||
MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing socks greeting\n");
|
||||
cce = "socks write failed";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY);
|
||||
|
||||
return wsi;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
send_hs:
|
||||
|
||||
if (wsi_piggyback &&
|
||||
!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
|
||||
/*
|
||||
* We are pipelining on an already-established connection...
|
||||
* we can skip tls establishment.
|
||||
*/
|
||||
|
||||
lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
|
||||
|
||||
/*
|
||||
* we can't send our headers directly, because they have to
|
||||
* be sent when the parent is writeable. The parent will check
|
||||
* for anybody on his client transaction queue that is in
|
||||
* LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
|
||||
*
|
||||
* If we are trying to do this too early, before the master
|
||||
* connection has written his own headers, then it will just
|
||||
* wait in the queue until it's possible to send them.
|
||||
*/
|
||||
lws_callback_on_writable(wsi_piggyback);
|
||||
lwsl_info("%s: wsi %p: waiting to send hdrs (par state 0x%x)\n",
|
||||
__func__, wsi, lwsi_state(wsi_piggyback));
|
||||
} else {
|
||||
lwsl_info("%s: wsi %p: client creating own connection\n",
|
||||
__func__, wsi);
|
||||
|
||||
/* we are making our own connection */
|
||||
if (!rawish)
|
||||
lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);
|
||||
else {
|
||||
/* for a method = "RAW" connection, this makes us
|
||||
* established */
|
||||
|
||||
/* clear his established timeout */
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
m = wsi->role_ops->adoption_cb[0];
|
||||
if (m) {
|
||||
n = user_callback_handle_rxflow(
|
||||
wsi->protocol->callback, wsi,
|
||||
m, wsi->user_space, NULL, 0);
|
||||
if (n < 0) {
|
||||
lwsl_info("LWS_CALLBACK_RAW_PROXY_CLI_ADOPT failed\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* service.c pollout processing wants this */
|
||||
wsi->hdr_parsing_completed = 1;
|
||||
|
||||
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
/*
|
||||
* provoke service to issue the handshake directly.
|
||||
*
|
||||
* we need to do it this way because in the proxy case, this is
|
||||
* the next state and executed only if and when we get a good
|
||||
* proxy response inside the state machine... but notice in
|
||||
* SSL case this may not have sent anything yet with 0 return,
|
||||
* and won't until many retries from main loop. To stop that
|
||||
* becoming endless, cover with a timeout.
|
||||
*/
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
assert(lws_socket_is_valid(wsi->desc.sockfd));
|
||||
|
||||
pfd.fd = wsi->desc.sockfd;
|
||||
pfd.events = LWS_POLLIN;
|
||||
pfd.revents = LWS_POLLIN;
|
||||
|
||||
n = lws_service_fd(context, &pfd);
|
||||
if (n < 0) {
|
||||
cce = "first service failed";
|
||||
goto failed;
|
||||
}
|
||||
if (n) /* returns 1 on failure after closing wsi */
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return wsi;
|
||||
|
||||
oom4:
|
||||
if (lwsi_role_client(wsi) /* && lwsi_state_est(wsi) */) {
|
||||
|
@ -734,6 +762,7 @@ failed1:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
|
||||
/**
|
||||
|
|
|
@ -759,7 +759,11 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
|||
if (ah)
|
||||
ah->http_response = n;
|
||||
|
||||
if (n == 301 || n == 302 || n == 303 || n == 307 || n == 308) {
|
||||
if (
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
!wsi->http.proxy_clientside &&
|
||||
#endif
|
||||
(n == 301 || n == 302 || n == 303 || n == 307 || n == 308)) {
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);
|
||||
if (!p) {
|
||||
cce = "HS: Redirect code but no Location";
|
||||
|
@ -1249,8 +1253,13 @@ spin_chunks:
|
|||
{
|
||||
struct lws *wsi_eff = lws_client_wsi_effective(wsi);
|
||||
|
||||
if (!wsi_eff->protocol_bind_balance ==
|
||||
if (
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
!wsi_eff->protocol_bind_balance ==
|
||||
!!wsi_eff->http.proxy_clientside &&
|
||||
#else
|
||||
!!wsi_eff->protocol_bind_balance &&
|
||||
#endif
|
||||
user_callback_handle_rxflow(wsi_eff->protocol->callback,
|
||||
wsi_eff, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
|
||||
wsi_eff->user_space, *buf, n)) {
|
||||
|
|
|
@ -329,3 +329,6 @@ enum {
|
|||
|
||||
int
|
||||
lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot);
|
||||
|
||||
struct lws *
|
||||
lws_client_connect_3(struct lws *wsi, struct lws *wsi_piggyback, ssize_t plen);
|
||||
|
|
|
@ -107,8 +107,10 @@ struct lws_role_ops role_ops_raw_file = {
|
|||
LWS_CALLBACK_RAW_ADOPT_FILE },
|
||||
/* rx_cb clnt, srv */ { LWS_CALLBACK_RAW_RX_FILE,
|
||||
LWS_CALLBACK_RAW_RX_FILE },
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE_FILE, 0 },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE_FILE, 0 },
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE_FILE,
|
||||
LWS_CALLBACK_RAW_WRITEABLE_FILE},
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE_FILE,
|
||||
LWS_CALLBACK_RAW_CLOSE_FILE},
|
||||
/* protocol_bind cb c, srv */ { LWS_CALLBACK_RAW_FILE_BIND_PROTOCOL,
|
||||
LWS_CALLBACK_RAW_FILE_BIND_PROTOCOL },
|
||||
/* protocol_unbind cb c, srv */ { LWS_CALLBACK_RAW_FILE_DROP_PROTOCOL,
|
||||
|
|
|
@ -119,7 +119,7 @@ rops_adoption_bind_raw_proxy(struct lws *wsi, int type,
|
|||
{
|
||||
/* no http but socket... must be raw skt */
|
||||
if ((type & LWS_ADOPT_HTTP) || !(type & LWS_ADOPT_SOCKET) ||
|
||||
!(type & LWS_ADOPT_FLAG_RAW_PROXY) || (type & _LWS_ADOPT_FINISH))
|
||||
(!(type & LWS_ADOPT_FLAG_RAW_PROXY)) || (type & _LWS_ADOPT_FINISH))
|
||||
return 0; /* no match */
|
||||
|
||||
if (type & LWS_ADOPT_FLAG_UDP)
|
||||
|
@ -160,10 +160,10 @@ rops_client_bind_raw_proxy(struct lws *wsi,
|
|||
|
||||
/* we are a fallback if nothing else matched */
|
||||
|
||||
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
|
||||
&role_ops_raw_proxy);
|
||||
// lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
|
||||
// &role_ops_raw_proxy);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -96,6 +96,11 @@ try_pollout:
|
|||
if (!(pollfd->revents & LWS_POLLOUT))
|
||||
return LWS_HPI_RET_HANDLED;
|
||||
|
||||
#if !defined(LWS_WITHOUT_CLIENT)
|
||||
if (lwsi_state(wsi) == LRS_WAITING_CONNECT)
|
||||
lws_client_connect_3(wsi, NULL, 0);
|
||||
#endif
|
||||
|
||||
/* one shot */
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_notice("%s a\n", __func__);
|
||||
|
@ -223,12 +228,14 @@ struct lws_role_ops role_ops_raw_skt = {
|
|||
#else
|
||||
NULL,
|
||||
#endif
|
||||
/* adoption_cb clnt, srv */ { LWS_CALLBACK_RAW_ADOPT,
|
||||
/* adoption_cb clnt, srv */ { LWS_CALLBACK_RAW_CONNECTED,
|
||||
LWS_CALLBACK_RAW_ADOPT },
|
||||
/* rx_cb clnt, srv */ { LWS_CALLBACK_RAW_RX,
|
||||
LWS_CALLBACK_RAW_RX },
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE, 0 },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE, 0 },
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE,
|
||||
LWS_CALLBACK_RAW_WRITEABLE},
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE,
|
||||
LWS_CALLBACK_RAW_CLOSE },
|
||||
/* protocol_bind cb c, srv */ { LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL,
|
||||
LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL },
|
||||
/* protocol_unbind cb c, srv */ { LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL,
|
||||
|
|
|
@ -8,4 +8,5 @@ api-test-lws_tokenize|Generic secure string tokenizer api
|
|||
api-test-fts|LWS Full-text Search api
|
||||
api-test-gencrypto|LWS Generic Crypto apis
|
||||
api-test-jose|LWS JOSE apis
|
||||
api-test-smtp_client|SMTP client for sending emails
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
set(SAMP lws-api-test-smtp_client)
|
||||
set(SRCS main.c)
|
||||
|
||||
# If we are being built as part of lws, confirm current build config supports
|
||||
# reqconfig, else skip building ourselves.
|
||||
#
|
||||
# If we are being built externally, confirm installed lws was configured to
|
||||
# support reqconfig, else error out with a helpful message about the problem.
|
||||
#
|
||||
MACRO(require_lws_config reqconfig _val result)
|
||||
|
||||
if (DEFINED ${reqconfig})
|
||||
if (${reqconfig})
|
||||
set (rq 1)
|
||||
else()
|
||||
set (rq 0)
|
||||
endif()
|
||||
else()
|
||||
set(rq 0)
|
||||
endif()
|
||||
|
||||
if (${_val} EQUAL ${rq})
|
||||
set(SAME 1)
|
||||
else()
|
||||
set(SAME 0)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
|
||||
if (${_val})
|
||||
message("${SAMP}: skipping as lws being built without ${reqconfig}")
|
||||
else()
|
||||
message("${SAMP}: skipping as lws built with ${reqconfig}")
|
||||
endif()
|
||||
set(${result} 0)
|
||||
else()
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES)
|
||||
set(MET ${SAME})
|
||||
else()
|
||||
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
|
||||
if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
|
||||
set(HAS_${reqconfig} 0)
|
||||
else()
|
||||
set(HAS_${reqconfig} 1)
|
||||
endif()
|
||||
if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
|
||||
set(MET 1)
|
||||
else()
|
||||
set(MET 0)
|
||||
endif()
|
||||
endif()
|
||||
if (NOT MET)
|
||||
if (${_val})
|
||||
message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
|
||||
else()
|
||||
message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
ENDMACRO()
|
||||
|
||||
set(requirements 1)
|
||||
require_lws_config(LWS_WITH_SMTP 1 requirements)
|
||||
|
||||
if (requirements)
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared)
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets)
|
||||
endif()
|
||||
endif()
|
29
minimal-examples/api-tests/api-test-smtp_client/README.md
Normal file
29
minimal-examples/api-tests/api-test-smtp_client/README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
# lws api test smtp client
|
||||
|
||||
Demonstrates how to send email through your local MTA
|
||||
|
||||
## build
|
||||
|
||||
Requires lws was built with `-DLWS_WITH_SMTP=1` at cmake.
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
Commandline option|Meaning
|
||||
---|---
|
||||
-d <loglevel>|Debug verbosity in decimal, eg, -d15
|
||||
-r <recipient@whatever.com>|Send the test email to this email address
|
||||
|
||||
|
||||
```
|
||||
$ ./lws-api-test-smtp_client -r andy@warmcat.com
|
||||
[2019/04/17 05:12:06:5293] USER: LWS API selftest: SMTP client
|
||||
[2019/04/17 05:12:06:5635] NOTICE: LGSSMTP_IDLE: connecting to 127.0.0.1:25
|
||||
[2019/04/17 05:12:06:6238] NOTICE: email_sent_or_failed: sent OK
|
||||
[2019/04/17 05:12:06:6394] USER: Completed: PASS
|
||||
|
||||
```
|
||||
|
137
minimal-examples/api-tests/api-test-smtp_client/main.c
Normal file
137
minimal-examples/api-tests/api-test-smtp_client/main.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* lws-api-test-smtp_client
|
||||
*
|
||||
* Written in 2010-2019 by Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
static int interrupted, result = 1;
|
||||
static const char *recip;
|
||||
|
||||
static void
|
||||
sigint_handler(int sig)
|
||||
{
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
email_sent_or_failed(struct lws_smtp_email *email, void *buf, size_t len)
|
||||
{
|
||||
/* you could examine email->data here */
|
||||
if (buf)
|
||||
lwsl_notice("%s: %.*s\n", __func__, (int)len, (const char *)buf);
|
||||
else
|
||||
lwsl_notice("%s:\n", __func__);
|
||||
|
||||
/* destroy any allocations in email */
|
||||
|
||||
free((char *)email->payload);
|
||||
|
||||
result = 0;
|
||||
interrupted = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int n = 1, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
lws_smtp_client_info_t sci;
|
||||
lws_smtp_client_t *smtpc;
|
||||
lws_smtp_email_t email;
|
||||
struct lws_vhost *vh;
|
||||
const char *p;
|
||||
|
||||
/* the normal lws init */
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
p = lws_cmdline_option(argc, argv, "-r");
|
||||
if (!p) {
|
||||
lwsl_err("-r <recipient email> is required\n");
|
||||
return 1;
|
||||
}
|
||||
recip = p;
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS API selftest: SMTP client\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
vh = lws_create_vhost(context, &info);
|
||||
if (!vh) {
|
||||
lwsl_err("Failed to create first vhost\n");
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
/* create the smtp client */
|
||||
|
||||
memset(&sci, 0, sizeof(sci));
|
||||
sci.data = NULL /* stmp client specific user data */;
|
||||
sci.abs = lws_abstract_get_by_name("raw_skt");
|
||||
sci.vh = vh;
|
||||
lws_strncpy(sci.ip, "127.0.0.1", sizeof(sci.ip));
|
||||
lws_strncpy(sci.helo, "lws-test-client", sizeof(sci.helo));
|
||||
|
||||
smtpc = lws_smtp_client_create(&sci);
|
||||
if (!smtpc) {
|
||||
lwsl_err("%s: failed to create SMTP client\n", __func__);
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
/* attach an email to it */
|
||||
|
||||
memset(&email, 0, sizeof(email));
|
||||
email.data = NULL /* email specific user data */;
|
||||
email.email_from = recip;
|
||||
email.email_to = "andy@warmcat.com";
|
||||
email.payload = malloc(2048);
|
||||
if (!email.payload) {
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
lws_snprintf((char *)email.payload, 2048,
|
||||
"From: noreply@example.com\n"
|
||||
"To: %s\n"
|
||||
"Subject: Test email for lws smtp-client\n"
|
||||
"\n"
|
||||
"Hello this was an api test for lws smtp-client\n"
|
||||
"\r\n.\r\n", recip);
|
||||
email.done = email_sent_or_failed;
|
||||
|
||||
if (lws_smtp_client_add_email(smtpc, &email)) {
|
||||
lwsl_err("%s: failed to add email\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* the usual lws event loop */
|
||||
|
||||
while (n >= 0 && !interrupted)
|
||||
n = lws_service(context, 1000);
|
||||
|
||||
bail:
|
||||
lws_smtp_client_destroy(&smtpc);
|
||||
bail1:
|
||||
lwsl_user("Completed: %s\n", result ? "FAIL" : "PASS");
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -432,7 +432,7 @@ lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd,
|
|||
"Hello, %s\n\n"
|
||||
"We received a password reset request from IP %s for this email,\n"
|
||||
"to confirm you want to do that, please click the link below.\n\n",
|
||||
lws_sql_purify(esc, vhd->email.email_from, sizeof(esc) - 1),
|
||||
lws_sql_purify(esc, vhd->email_from, sizeof(esc) - 1),
|
||||
lws_sql_purify(esc1, u.username, sizeof(esc1) - 1),
|
||||
lws_sql_purify(esc2, u.email, sizeof(esc2) - 1),
|
||||
lws_sql_purify(esc3, u.username, sizeof(esc3) - 1),
|
||||
|
@ -586,7 +586,7 @@ lwsgs_handler_register_form(struct per_vhost_data__gs *vhd,
|
|||
"automated email, you can contact a real person at\n"
|
||||
"%s.\n"
|
||||
"\n.\n",
|
||||
lws_sql_purify(esc, vhd->email.email_from, sizeof(esc) - 1),
|
||||
lws_sql_purify(esc, vhd->email_from, sizeof(esc) - 1),
|
||||
lws_sql_purify(esc1, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc1) - 1),
|
||||
lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
|
||||
lws_sql_purify(esc3, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc3) - 1),
|
||||
|
|
|
@ -62,7 +62,7 @@ struct lwsgs_user {
|
|||
};
|
||||
|
||||
struct per_vhost_data__gs {
|
||||
struct lws_email email;
|
||||
lws_smtp_client_t *smtp_client;
|
||||
struct lwsgs_user u;
|
||||
struct lws_context *context;
|
||||
char session_db[256];
|
||||
|
@ -72,14 +72,14 @@ struct per_vhost_data__gs {
|
|||
char email_title[128];
|
||||
char email_template[128];
|
||||
char email_confirm_url[128];
|
||||
lwsgw_hash admin_password_sha1;
|
||||
char email_from[128];
|
||||
lwsgw_hash admin_password_sha256;
|
||||
sqlite3 *pdb;
|
||||
int timeout_idle_secs;
|
||||
int timeout_absolute_secs;
|
||||
int timeout_anon_absolute_secs;
|
||||
int timeout_email_secs;
|
||||
time_t last_session_expire;
|
||||
char email_inited;
|
||||
};
|
||||
|
||||
struct per_session_data__gs {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* ws protocol handler plugin for "generic sessions"
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -50,7 +50,7 @@ struct lwsgs_fill_args {
|
|||
};
|
||||
|
||||
static const struct lws_protocols protocols[];
|
||||
|
||||
#if 0
|
||||
static int
|
||||
lwsgs_lookup_callback_email(void *priv, int cols, char **col_val,
|
||||
char **col_name)
|
||||
|
@ -92,11 +92,13 @@ lwsgs_email_cb_get_body(struct lws_email *email, char *buf, int len)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static int
|
||||
lwsgs_email_cb_sent(struct lws_email *email)
|
||||
lwsgs_smtp_client_done(struct lws_smtp_email *e, void *buf, size_t len)
|
||||
{
|
||||
struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)email->data;
|
||||
struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)e->data;
|
||||
char s[200], esc[50];
|
||||
|
||||
/* mark the user as having sent the verification email */
|
||||
|
@ -120,9 +122,10 @@ lwsgs_email_cb_sent(struct lws_email *email)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#if 0
|
||||
static int
|
||||
lwsgs_email_cb_on_next(struct lws_email *email)
|
||||
lwsgs_smtp_send_pending(struct lws_email *email)
|
||||
{
|
||||
struct per_vhost_data__gs *vhd = lws_container_of(email,
|
||||
struct per_vhost_data__gs, email);
|
||||
|
@ -181,7 +184,7 @@ lwsgs_email_cb_on_next(struct lws_email *email)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct lwsgs_subst_args
|
||||
{
|
||||
|
@ -252,6 +255,7 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
struct lws_session_info *sinfo;
|
||||
char s[LWSGS_EMAIL_CONTENT_SIZE];
|
||||
unsigned char *p, *start, *end;
|
||||
lws_smtp_client_info_t sci;
|
||||
sqlite3_stmt *sm;
|
||||
lwsgw_hash sid;
|
||||
const char *cp;
|
||||
|
@ -271,15 +275,13 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
vhd->timeout_absolute_secs = 36000;
|
||||
vhd->timeout_anon_absolute_secs = 1200;
|
||||
vhd->timeout_email_secs = 24 * 3600;
|
||||
strcpy(vhd->email.email_helo, "unconfigured.com");
|
||||
strcpy(vhd->email.email_from, "noreply@unconfigured.com");
|
||||
strcpy(vhd->email_title, "Registration Email from unconfigured");
|
||||
strcpy(vhd->email.email_smtp_ip, "127.0.0.1");
|
||||
|
||||
vhd->email.on_next = lwsgs_email_cb_on_next;
|
||||
vhd->email.on_get_body = lwsgs_email_cb_get_body;
|
||||
vhd->email.on_sent = lwsgs_email_cb_sent;
|
||||
vhd->email.data = (void *)vhd;
|
||||
memset(&sci, 0, sizeof(sci));
|
||||
|
||||
strcpy(sci.helo, "unconfigured.com");
|
||||
strcpy(sci.ip, "127.0.0.1");
|
||||
strcpy(vhd->email_from, "noreply@unconfigured.com");
|
||||
strcpy(vhd->email_title, "Registration Email from unconfigured");
|
||||
|
||||
pvo = (const struct lws_protocol_vhost_options *)in;
|
||||
while (pvo) {
|
||||
|
@ -287,8 +289,8 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
lws_strncpy(vhd->admin_user, pvo->value,
|
||||
sizeof(vhd->admin_user));
|
||||
if (!strcmp(pvo->name, "admin-password-sha1"))
|
||||
lws_strncpy(vhd->admin_password_sha1.id, pvo->value,
|
||||
sizeof(vhd->admin_password_sha1.id));
|
||||
lws_strncpy(vhd->admin_password_sha256.id, pvo->value,
|
||||
sizeof(vhd->admin_password_sha256.id));
|
||||
if (!strcmp(pvo->name, "session-db"))
|
||||
lws_strncpy(vhd->session_db, pvo->value,
|
||||
sizeof(vhd->session_db));
|
||||
|
@ -296,11 +298,10 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
lws_strncpy(vhd->confounder, pvo->value,
|
||||
sizeof(vhd->confounder));
|
||||
if (!strcmp(pvo->name, "email-from"))
|
||||
lws_strncpy(vhd->email.email_from, pvo->value,
|
||||
sizeof(vhd->email.email_from));
|
||||
lws_strncpy(vhd->email_from, pvo->value,
|
||||
sizeof(vhd->email_from));
|
||||
if (!strcmp(pvo->name, "email-helo"))
|
||||
lws_strncpy(vhd->email.email_helo, pvo->value,
|
||||
sizeof(vhd->email.email_helo));
|
||||
lws_strncpy(sci.helo, pvo->value, sizeof(sci.helo));
|
||||
if (!strcmp(pvo->name, "email-template"))
|
||||
lws_strncpy(vhd->email_template, pvo->value,
|
||||
sizeof(vhd->email_template));
|
||||
|
@ -314,8 +315,7 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
lws_strncpy(vhd->email_confirm_url, pvo->value,
|
||||
sizeof(vhd->email_confirm_url));
|
||||
if (!strcmp(pvo->name, "email-server-ip"))
|
||||
lws_strncpy(vhd->email.email_smtp_ip, pvo->value,
|
||||
sizeof(vhd->email.email_smtp_ip));
|
||||
lws_strncpy(sci.ip, pvo->value, sizeof(sci.ip));
|
||||
|
||||
if (!strcmp(pvo->name, "timeout-idle-secs"))
|
||||
vhd->timeout_idle_secs = atoi(pvo->value);
|
||||
|
@ -328,11 +328,11 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
pvo = pvo->next;
|
||||
}
|
||||
if (!vhd->admin_user[0] ||
|
||||
!vhd->admin_password_sha1.id[0] ||
|
||||
!vhd->admin_password_sha256.id[0] ||
|
||||
!vhd->session_db[0]) {
|
||||
lwsl_err("generic-sessions: "
|
||||
"You must give \"admin-user\", "
|
||||
"\"admin-password-sha1\", "
|
||||
"\"admin-password-sha256\", "
|
||||
"and \"session_db\" per-vhost options\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -401,10 +401,16 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
return 1;
|
||||
}
|
||||
|
||||
lws_email_init(&vhd->email, lws_uv_getloop(vhd->context, 0),
|
||||
LWSGS_EMAIL_CONTENT_SIZE);
|
||||
sci.data = vhd;
|
||||
sci.abs = lws_abstract_get_by_name("raw_skt");
|
||||
sci.vh = lws_get_vhost(wsi);
|
||||
|
||||
vhd->smtp_client = lws_smtp_client_create(&sci);
|
||||
if (!vhd->smtp_client) {
|
||||
lwsl_err("%s: failed to create SMTP client\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
vhd->email_inited = 1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
|
@ -413,16 +419,15 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
sqlite3_close(vhd->pdb);
|
||||
vhd->pdb = NULL;
|
||||
}
|
||||
if (vhd->email_inited) {
|
||||
lws_email_destroy(&vhd->email);
|
||||
vhd->email_inited = 0;
|
||||
}
|
||||
if (vhd->smtp_client)
|
||||
lws_smtp_client_destroy(&vhd->smtp_client);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
if (!pss->check_response)
|
||||
break;
|
||||
n = lws_write(wsi, (unsigned char *)&pss->check_response_value, 1, LWS_WRITE_HTTP_FINAL);
|
||||
n = lws_write(wsi, (unsigned char *)&pss->check_response_value,
|
||||
1, LWS_WRITE_HTTP_FINAL);
|
||||
if (n != 1)
|
||||
return -1;
|
||||
goto try_to_reuse;
|
||||
|
@ -610,7 +615,7 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
goto reg_done;
|
||||
}
|
||||
/* get the email monitor to take a look */
|
||||
lws_email_check(&vhd->email);
|
||||
lws_smtp_client_kick(vhd->smtp_client);
|
||||
n = FGS_FORGOT_GOOD;
|
||||
goto reg_done;
|
||||
}
|
||||
|
@ -632,7 +637,7 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
n = FGS_REG_GOOD;
|
||||
|
||||
/* get the email monitor to take a look */
|
||||
lws_email_check(&vhd->email);
|
||||
lws_smtp_client_kick(vhd->smtp_client);
|
||||
}
|
||||
reg_done:
|
||||
lws_strncpy(pss->onward, lws_spa_get_string(pss->spa, n),
|
||||
|
|
|
@ -50,7 +50,7 @@ lwsgw_check_admin(struct per_vhost_data__gs *vhd,
|
|||
lws_SHA1((unsigned char *)password, strlen(password), hash_bin.bin);
|
||||
sha1_to_lwsgw_hash(hash_bin.bin, &pw_hash);
|
||||
|
||||
return !strcmp(vhd->admin_password_sha1.id, pw_hash.id);
|
||||
return !strcmp(vhd->admin_password_sha256.id, pw_hash.id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue