1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-16 00:00:07 +01:00
libwebsockets/lib/abstract/transports/raw-skt.c

334 lines
7.3 KiB
C
Raw Normal View History

2019-04-21 19:57:19 +01:00
/*
* 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)
2019-04-21 19:57:19 +01:00
{
lws_atrs_priv_t *priv = (lws_atrs_priv_t *)abs_priv;
struct lws_client_connect_info i;
const lws_token_map_t *tm;
2019-04-21 19:57:19 +01:00
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);
2019-04-21 19:57:19 +01:00
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 */
};