aboutsummaryrefslogtreecommitdiff
path: root/lib/abstract
diff options
context:
space:
mode:
authorAndy Green <andy@warmcat.com>2019-04-21 19:57:19 +0100
committerAndy Green <andy@warmcat.com>2019-05-04 08:28:31 +0100
commit8d473ad78c4d816d3e872f6d2d67e59a0e92b84f (patch)
treefd19ec0a79aeebce5d108819537393fd0334c6ae /lib/abstract
parentae6346db64cda88128a964d6df8ec302a3818a54 (diff)
downloadlibwebsockets-8d473ad78c4d816d3e872f6d2d67e59a0e92b84f.tar.gz
smtp: make abstract
Diffstat (limited to 'lib/abstract')
-rw-r--r--lib/abstract/abstract.c52
-rw-r--r--lib/abstract/private.h68
-rw-r--r--lib/abstract/smtp/private.h51
-rw-r--r--lib/abstract/smtp/smtp.c395
-rw-r--r--lib/abstract/transports/raw-skt.c309
5 files changed, 875 insertions, 0 deletions
diff --git a/lib/abstract/abstract.c b/lib/abstract/abstract.c
new file mode 100644
index 00000000..2a602cf7
--- /dev/null
+++ b/lib/abstract/abstract.c
@@ -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;
+}
diff --git a/lib/abstract/private.h b/lib/abstract/private.h
new file mode 100644
index 00000000..4962268d
--- /dev/null
+++ b/lib/abstract/private.h
@@ -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;
+
+
diff --git a/lib/abstract/smtp/private.h b/lib/abstract/smtp/private.h
new file mode 100644
index 00000000..bbc51f85
--- /dev/null
+++ b/lib/abstract/smtp/private.h
@@ -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;
+
diff --git a/lib/abstract/smtp/smtp.c b/lib/abstract/smtp/smtp.c
new file mode 100644
index 00000000..988700f8
--- /dev/null
+++ b/lib/abstract/smtp/smtp.c
@@ -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);
+}
diff --git a/lib/abstract/transports/raw-skt.c b/lib/abstract/transports/raw-skt.c
new file mode 100644
index 00000000..739b7a0d
--- /dev/null
+++ b/lib/abstract/transports/raw-skt.c
@@ -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 */
+};