1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-23 00:00:06 +01:00
libwebsockets/lib/abstract/transports/raw-skt.c
Andy Green a72b422be3 abstract: add abstract transport tokens
SMTP was improved to use the new abstract stuff a while ago,
but it was only implemented with raw socket abstract transport,
and a couple of 'api cheats' remained passing network information
for the peer connection through the supposedly abstract apis.

This patch adds a flexible generic token array to supply
abstract transport-specific information through the abstract apis,
removing the network information from the abstract connect() op.

The SMTP minimal example is modified to use this new method to
pass the network information.

The abstract transport struct was opaque, but there are real
uses to override it in user code, so this patch also makes it
part of the public abi.
2019-06-19 19:10:14 +01:00

333 lines
7.3 KiB
C

/*
* 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 lws_token_map_t *token_map)
{
lws_atrs_priv_t *priv = (lws_atrs_priv_t *)abs_priv;
struct lws_client_connect_info i;
const lws_token_map_t *tm;
if (priv->connecting)
return 0;
if (priv->established) {
lws_set_timeout(priv->wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 5);
return 0;
}
memset(&i, 0, sizeof(i));
/* address and port are passed-in using the abstract transport tokens */
tm = lws_abstract_get_token(token_map, LTMI_PEER_DNS_ADDRESS);
if (!tm) {
lwsl_notice("%s: raw_skt needs LTMI_PEER_DNS_ADDRESS\n",
__func__);
return 1;
}
i.address = tm->u.value;
tm = lws_abstract_get_token(token_map, LTMI_PEER_PORT);
if (!tm) {
lwsl_notice("%s: raw_skt needs LTMI_PEER_PORT\n", __func__);
return 1;
}
i.port = tm->u.lvalue;
/* optional */
i.ssl_connection = 0;
tm = lws_abstract_get_token(token_map, LTMI_PEER_TLS_FLAGS);
if (tm)
i.ssl_connection = tm->u.lvalue;
lwsl_debug("%s: raw_skt priv %p connecting to %s:%u %p\n",
__func__, priv, i.address, i.port, vh->context);
i.path = "";
i.vhost = vh;
i.method = "RAW";
i.userdata = priv;
i.host = i.address;
i.pwsi = &priv->wsi;
i.origin = i.address;
i.context = vh->context;
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 */
};