1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-30 00:00:16 +01:00

raw: tls conns

Raw + tls needs a little extra handling during connect.
This commit is contained in:
Andy Green 2022-01-25 19:31:36 +00:00
parent 02f7e06776
commit 3d98e29518
3 changed files with 306 additions and 5 deletions

View file

@ -24,6 +24,57 @@
#include <private-lib-core.h>
#if defined(LWS_WITH_CLIENT)
static int
lws_raw_skt_connect(struct lws *wsi)
{
int n;
#if defined(LWS_WITH_TLS)
const char *cce = NULL;
char ccebuf[128];
#if !defined(LWS_WITH_SYS_ASYNC_DNS)
switch (lws_client_create_tls(wsi, &cce, 1)) {
#else
switch (lws_client_create_tls(wsi, &cce, 0)) {
#endif
case CCTLS_RETURN_ERROR:
lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
return -1;
case CCTLS_RETURN_RETRY:
return 0;
case CCTLS_RETURN_DONE:
break;
}
if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
n = lws_ssl_client_connect2(wsi, ccebuf, sizeof(ccebuf));
if (n < 0) {
lws_inform_client_conn_fail(wsi, (void *)ccebuf,
strlen(ccebuf));
return -1;
}
if (n != 1)
return 0; /* wait */
}
#endif
n = user_callback_handle_rxflow(wsi->a.protocol->callback,
wsi, wsi->role_ops->adoption_cb[lwsi_role_server(wsi)],
wsi->user_space, NULL, 0);
if (n) {
lws_inform_client_conn_fail(wsi, (void *)"user", 4);
return 1;
}
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
lwsi_set_state(wsi, LRS_ESTABLISHED);
return 1; /* success */
}
#endif
static int
rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
struct lws_pollfd *pollfd)
@ -82,6 +133,14 @@ rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
case LRS_WAITING_CONNECT:
goto nope;
case LRS_WAITING_SSL:
#if defined(LWS_WITH_CLIENT)
n = lws_raw_skt_connect(wsi);
if (n < 0)
goto fail;
#endif
break;
#if defined(LWS_WITH_SOCKS5)
/* SOCKS Greeting Reply */
@ -177,16 +236,21 @@ try_pollout:
return LWS_HPI_RET_HANDLED;
#if defined(LWS_WITH_CLIENT)
if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
!lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL))
if (lwsi_state(wsi) == LRS_WAITING_CONNECT) {
if (!lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL))
return LWS_HPI_RET_WSI_ALREADY_DIED;
if (lws_raw_skt_connect(wsi) < 0)
goto fail;
}
#endif
if (lwsi_state(wsi) == LRS_WAITING_SSL)
return LWS_HPI_RET_HANDLED;
/* one shot */
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
lwsl_notice("%s a\n", __func__);
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
goto fail;
}
/* clear back-to-back write detection */
wsi->could_have_pending = 0;

View file

@ -0,0 +1,23 @@
project(lws-minimal-raw-client C)
cmake_minimum_required(VERSION 2.8.12)
find_package(libwebsockets CONFIG REQUIRED)
list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
include(CheckCSourceCompiles)
include(LwsCheckRequirements)
set(SAMP lws-minimal-raw-client)
set(SRCS main.c)
set(requirements 1)
require_lws_config(LWS_WITH_CLIENT 1 requirements)
if (requirements)
add_executable(${SAMP} ${SRCS})
if (websockets_shared)
target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
add_dependencies(${SAMP} websockets_shared)
else()
target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
endif()
endif()

View file

@ -0,0 +1,214 @@
/*
* lws-minimal-raw-client
*
* Written in 2010-2022 by Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* This demonstrates connecting a "raw" client connection
*/
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
#if !defined(WIN32)
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if !defined(WIN32)
#include <unistd.h>
#endif
#include <errno.h>
#include <assert.h>
static struct lws *raw_wsi, *stdin_wsi;
static uint8_t buf[LWS_PRE + 4096];
static int waiting, interrupted;
static struct lws_context *context;
static int us_wait_after_input_close = LWS_USEC_PER_SEC / 10;
static const char *server = "libwebsockets.org", *port = "443";
static int
callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
const char *cp = (const char *)in;
switch (reason) {
/* callbacks related to file descriptor */
case LWS_CALLBACK_RAW_ADOPT_FILE:
lwsl_user("LWS_CALLBACK_RAW_ADOPT_FILE\n");
break;
case LWS_CALLBACK_RAW_CLOSE_FILE:
lwsl_user("LWS_CALLBACK_RAW_CLOSE_FILE\n");
/* stdin close, wait 1s then close the raw skt */
stdin_wsi = NULL; /* invalid now we close */
if (raw_wsi)
lws_set_timer_usecs(raw_wsi, us_wait_after_input_close);
else {
interrupted = 1;
lws_cancel_service(context);
}
break;
case LWS_CALLBACK_RAW_RX_FILE:
lwsl_user("LWS_CALLBACK_RAW_RX_FILE\n");
waiting = (int)read(0, buf, sizeof(buf));
lwsl_notice("raw file read %d\n", waiting);
if (waiting < 0)
return -1;
if (raw_wsi)
lws_callback_on_writable(raw_wsi);
lws_rx_flow_control(wsi, 0);
break;
/* callbacks related to raw socket descriptor */
case LWS_CALLBACK_RAW_ADOPT:
lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_RAW_CONNECTED:
lwsl_user("LWS_CALLBACK_RAW_CONNECTED\n");
break;
case LWS_CALLBACK_RAW_CLOSE:
lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
/*
* If the socket to the remote server closed, we must close
* and drop any remaining stdin
*/
interrupted = 1;
lws_cancel_service(context);
/* our pointer to this wsi is invalid now we close */
raw_wsi = NULL;
break;
case LWS_CALLBACK_RAW_RX:
lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
while (len--)
putchar(*cp++);
fflush(stdout);
break;
case LWS_CALLBACK_RAW_WRITEABLE:
lwsl_user("LWS_CALLBACK_RAW_WRITEABLE\n");
// lwsl_hexdump_info(buf, waiting);
if (!waiting)
break;
if (stdin_wsi)
lws_rx_flow_control(stdin_wsi, 1);
if (lws_write(wsi, buf, (unsigned int)waiting, LWS_WRITE_RAW) != waiting) {
lwsl_notice("%s: raw skt write failed\n", __func__);
return -1;
}
break;
case LWS_CALLBACK_TIMER:
lwsl_user("LWS_CALLBACK_TIMER\n");
interrupted = 1;
lws_cancel_service(context);
return -1;
default:
break;
}
return 0;
}
static struct lws_protocols protocols[] = {
{ "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 },
LWS_PROTOCOL_LIST_TERM
};
static int
system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
int current, int target)
{
struct lws_client_connect_info i;
if (current != LWS_SYSTATE_OPERATIONAL ||
target != LWS_SYSTATE_OPERATIONAL)
return 0;
memset(&i, 0, sizeof i);
i.context = context;
i.method = "RAW";
i.ssl_connection = LCCSCF_USE_SSL;
i.alpn = "http/1.1";
i.address = server;
i.host = server;
i.port = atoi(port);
i.local_protocol_name = "raw-test";
waiting = lws_snprintf((char *)buf, sizeof(buf), "GET / HTTP/1.1\xaHost: libwebsockets.org\xa\xa");
if (!lws_client_connect_via_info(&i)) {
lwsl_err("Client creation failed\n");
interrupted = 1;
}
return 0;
}
void sigint_handler(int sig)
{
interrupted = 1;
}
int main(int argc, const char **argv)
{
struct lws_context_creation_info info;
const char *p;
int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
system_notify_cb, "app" };
lws_state_notify_link_t *na[] = { &notifier, NULL };
signal(SIGINT, sigint_handler);
if ((p = lws_cmdline_option(argc, argv, "-d")))
logs = atoi(p);
lws_set_log_level(logs, NULL);
lwsl_user("LWS minimal raw client\n");
memset(&info, 0, sizeof info);
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.port = CONTEXT_PORT_NO_LISTEN_SERVER;
info.protocols = protocols;
info.register_notifier_list = na;
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
}
while (n >= 0 && !interrupted)
n = lws_service(context, 0);
lwsl_user("%s: destroying context\n", __func__);
lws_context_destroy(context);
return 0;
}