mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
minimal: minimal-raw-adopt-tcp
This commit is contained in:
parent
feeca915b9
commit
9cf641dece
7 changed files with 318 additions and 5 deletions
|
@ -28,9 +28,6 @@
|
|||
/* Define to 1 if you have the <in6addr.h> header file. */
|
||||
#cmakedefine LWS_HAVE_IN6ADDR_H
|
||||
|
||||
/* Define to 1 if you have the `ssl' library (-lssl). */
|
||||
//#cmakedefine LWS_HAVE_LIBSSL
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#cmakedefine LWS_HAVE_MALLOC
|
||||
|
|
|
@ -3295,7 +3295,9 @@ struct lws_client_connect_info {
|
|||
/**< UNUSED... provide in info.extensions at context creation time */
|
||||
const char *method;
|
||||
/**< if non-NULL, do this http method instead of ws[s] upgrade.
|
||||
* use "GET" to be a simple http client connection */
|
||||
* use "GET" to be a simple http client connection. "RAW" gets
|
||||
* you a connected socket that lws itself will leave alone once
|
||||
* connected. */
|
||||
struct lws *parent_wsi;
|
||||
/**< if another wsi is responsible for this connection, give it here.
|
||||
* this is used to make sure if the parent closes so do any
|
||||
|
|
|
@ -70,8 +70,10 @@ lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd)
|
|||
}
|
||||
#endif
|
||||
rlen = sizeof(addr);
|
||||
if (getpeername(sockfd, (struct sockaddr*)&addr, &rlen))
|
||||
if (getpeername(sockfd, (struct sockaddr*)&addr, &rlen)) {
|
||||
lwsl_notice("%s: getpeername failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (af == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|name|demonstrates|
|
||||
---|---
|
||||
minimal-raw-adopt-tcp|Shows how to have lws adopt an existing tcp socket something else had connected
|
||||
minimal-raw-file|Shows how to adopt a file descriptor (device node, fifo, file, etc) into the lws event loop and handle events
|
||||
minimal-raw-vhost|Shows how to set up a vhost that listens and accepts RAW socket connections
|
||||
|
||||
|
|
76
minimal-examples/raw/minimal-raw-adopt-tcp/CMakeLists.txt
Normal file
76
minimal-examples/raw/minimal-raw-adopt-tcp/CMakeLists.txt
Normal file
|
@ -0,0 +1,76 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
set(SAMP lws-minimal-raw-adopt-tcp)
|
||||
set(SRCS minimal-raw-adopt-tcp.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_WITHOUT_SERVER 0 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()
|
54
minimal-examples/raw/minimal-raw-adopt-tcp/README.md
Normal file
54
minimal-examples/raw/minimal-raw-adopt-tcp/README.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
# lws minimal ws server raw adopt tcp
|
||||
|
||||
This example is only meaningful if you are integrating lws in another
|
||||
app which generates its own connected sockets. In some cases you may
|
||||
want lws to "adopt" the socket.
|
||||
|
||||
(If you simply want a connected client raw socket using lws alone, you
|
||||
can just use lws_client_connect_via_info() with info.method = "RAW".
|
||||
http-client/minimal-http-client shows how to do that, just set
|
||||
info.method to "RAW".)
|
||||
|
||||
This example demonstrates how to adopt a foreign, connected socket into lws
|
||||
as a raw wsi, bound to a specific lws protocol.
|
||||
|
||||
The example connects a socket itself to libwebsockets.org:80, and then
|
||||
has lws adopt it as a raw wsi. The lws protocol writes "GET / HTTP/1.1"
|
||||
to the socket and hexdumps what was sent back.
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
```
|
||||
$ ./lws-minimal-raw-adopt-tcp
|
||||
[2018/03/23 09:03:57:1960] USER: LWS minimal raw adopt tcp
|
||||
[2018/03/23 09:03:57:1961] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 off
|
||||
[2018/03/23 09:03:57:2079] USER: Starting connect...
|
||||
[2018/03/23 09:03:57:4963] USER: Connected...
|
||||
[2018/03/23 09:03:57:4963] USER: LWS_CALLBACK_RAW_ADOPT
|
||||
[2018/03/23 09:03:57:7842] USER: LWS_CALLBACK_RAW_RX (186)
|
||||
[2018/03/23 09:03:57:7842] NOTICE:
|
||||
[2018/03/23 09:03:57:7842] NOTICE: 0000: 48 54 54 50 2F 31 2E 31 20 33 30 31 20 52 65 64 HTTP/1.1 301 Red
|
||||
[2018/03/23 09:03:57:7842] NOTICE: 0010: 69 72 65 63 74 0D 0A 73 65 72 76 65 72 3A 20 6C irect..server: l
|
||||
[2018/03/23 09:03:57:7842] NOTICE: 0020: 77 73 77 73 0D 0A 53 74 72 69 63 74 2D 54 72 61 wsws..Strict-Tra
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 0030: 6E 73 70 6F 72 74 2D 53 65 63 75 72 69 74 79 3A nsport-Security:
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 0040: 20 6D 61 78 2D 61 67 65 3D 31 35 37 36 38 30 30 max-age=1576800
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 0050: 30 20 3B 20 69 6E 63 6C 75 64 65 53 75 62 44 6F 0 ; includeSubDo
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 0060: 6D 61 69 6E 73 0D 0A 6C 6F 63 61 74 69 6F 6E 3A mains..location:
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 0070: 20 68 74 74 70 73 3A 2F 2F 6C 69 62 77 65 62 73 https://libwebs
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 0080: 6F 63 6B 65 74 73 2E 6F 72 67 0D 0A 63 6F 6E 74 ockets.org..cont
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 0090: 65 6E 74 2D 74 79 70 65 3A 20 74 65 78 74 2F 68 ent-type: text/h
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 00A0: 74 6D 6C 0D 0A 63 6F 6E 74 65 6E 74 2D 6C 65 6E tml..content-len
|
||||
[2018/03/23 09:03:57:7843] NOTICE: 00B0: 67 74 68 3A 20 30 0D 0A 0D 0A gth: 0....
|
||||
[2018/03/23 09:03:57:7843] NOTICE:
|
||||
[2018/03/23 09:04:03:3627] USER: LWS_CALLBACK_RAW_CLOSE
|
||||
|
||||
```
|
||||
|
||||
Note the example does everything itself, after 5s idle the remote server closes the connection
|
||||
after which the example continues until you ^C it.
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* lws-minimal-raw-adopt-tcp
|
||||
*
|
||||
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* This demonstrates integrating somebody else's connected tcp
|
||||
* socket into the lws event loop as a RAW wsi. It's interesting in
|
||||
* the kind of situation where you already have a connected socket
|
||||
* in your application, and you need to hand it over to lws to deal with.
|
||||
*
|
||||
* Lws supports "adopting" these foreign sockets.
|
||||
*
|
||||
* If you simply want a connected client raw socket using lws alone, you
|
||||
* can just use lws_client_connect_via_info() with info.method = "RAW".
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static int
|
||||
callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
|
||||
switch (reason) {
|
||||
|
||||
/* 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_CLOSE:
|
||||
lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_RX:
|
||||
lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
|
||||
lwsl_hexdump_level(LLL_NOTICE, in, len);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_WRITEABLE:
|
||||
if (lws_write(wsi,
|
||||
(uint8_t *)"GET / HTTP/1.1\xd\xa\xd\xa", 18,
|
||||
LWS_WRITE_RAW) != 18) {
|
||||
lwsl_notice("%s: raw write failed\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct lws_protocols protocols[] = {
|
||||
{ "raw-test", callback_raw_test, 0, 0 },
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
static int interrupted;
|
||||
|
||||
void sigint_handler(int sig)
|
||||
{
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
lws_sock_file_fd_type sock;
|
||||
struct addrinfo h, *r, *rp;
|
||||
struct lws_vhost *vhost;
|
||||
int n = 0;
|
||||
|
||||
lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
||||
/* for LLL_ verbosity above NOTICE to be built into lws,
|
||||
* lws must have been configured and built with
|
||||
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
|
||||
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
|
||||
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
|
||||
/* | LLL_DEBUG */, NULL);
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
||||
|
||||
lwsl_user("LWS minimal raw adopt tcp\n");
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
info.port = 7681;
|
||||
info.protocols = protocols;
|
||||
|
||||
vhost = lws_create_vhost(context, &info);
|
||||
if (!vhost) {
|
||||
lwsl_err("lws vhost creation failed\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect our own "foreign" socket to libwebsockets.org:80
|
||||
*
|
||||
* Normally you would do this with lws_client_connect_via_info() inside
|
||||
* the lws event loop, hiding all this detail. But this example
|
||||
* demonstrates how to integrate an externally-connected "foreign"
|
||||
* socket, so we create one by hand.
|
||||
*/
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
h.ai_socktype = SOCK_STREAM;
|
||||
h.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
n = getaddrinfo("libwebsockets.org", "80", &h, &r);
|
||||
if (n) {
|
||||
lwsl_err("%s: problem resolving libwebsockets.org: %s\n", __func__, gai_strerror(n));
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (rp = r; rp; rp = rp->ai_next) {
|
||||
sock.sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if (sock.sockfd >= 0)
|
||||
break;
|
||||
}
|
||||
if (!rp) {
|
||||
lwsl_err("%s: unable to create INET socket\n", __func__);
|
||||
freeaddrinfo(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_user("Starting connect...\n");
|
||||
if (connect(sock.sockfd, rp->ai_addr, sizeof(*rp->ai_addr)) < 0) {
|
||||
lwsl_err("%s: unable to connect to libwebsockets.org:80\n", __func__);
|
||||
freeaddrinfo(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
freeaddrinfo(r);
|
||||
signal(SIGINT, sigint_handler);
|
||||
lwsl_user("Connected...\n");
|
||||
|
||||
/* our foreign socket is connected... adopt it into lws */
|
||||
|
||||
if (!lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_SOCKET, sock,
|
||||
protocols[0].name, NULL)) {
|
||||
lwsl_err("%s: foreign socket adoption failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
while (n >= 0 && !interrupted)
|
||||
n = lws_service(context, 1000);
|
||||
|
||||
bail:
|
||||
lws_context_destroy(context);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue