1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-minimal-raw-netcat 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2019 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * This demonstrates sending stdin to a remote socket and printing 10d4afb5ceSopenharmony_ci * what is returned to stdout. 11d4afb5ceSopenharmony_ci * 12d4afb5ceSopenharmony_ci * All the logging is on stderr, so you can tune it out with 2>log 13d4afb5ceSopenharmony_ci * or whatever. 14d4afb5ceSopenharmony_ci */ 15d4afb5ceSopenharmony_ci 16d4afb5ceSopenharmony_ci#include <libwebsockets.h> 17d4afb5ceSopenharmony_ci#include <string.h> 18d4afb5ceSopenharmony_ci#include <signal.h> 19d4afb5ceSopenharmony_ci#if !defined(WIN32) 20d4afb5ceSopenharmony_ci#include <sys/socket.h> 21d4afb5ceSopenharmony_ci#include <sys/types.h> 22d4afb5ceSopenharmony_ci#include <netinet/in.h> 23d4afb5ceSopenharmony_ci#include <netdb.h> 24d4afb5ceSopenharmony_ci#include <arpa/inet.h> 25d4afb5ceSopenharmony_ci#endif 26d4afb5ceSopenharmony_ci#include <stdio.h> 27d4afb5ceSopenharmony_ci#include <string.h> 28d4afb5ceSopenharmony_ci#include <stdlib.h> 29d4afb5ceSopenharmony_ci#if !defined(WIN32) 30d4afb5ceSopenharmony_ci#include <unistd.h> 31d4afb5ceSopenharmony_ci#endif 32d4afb5ceSopenharmony_ci#include <errno.h> 33d4afb5ceSopenharmony_ci 34d4afb5ceSopenharmony_cistatic struct lws *raw_wsi, *stdin_wsi; 35d4afb5ceSopenharmony_cistatic uint8_t buf[LWS_PRE + 4096]; 36d4afb5ceSopenharmony_cistatic int waiting, interrupted; 37d4afb5ceSopenharmony_cistatic struct lws_context *context; 38d4afb5ceSopenharmony_cistatic int us_wait_after_input_close = LWS_USEC_PER_SEC / 10; 39d4afb5ceSopenharmony_ci 40d4afb5ceSopenharmony_cistatic int 41d4afb5ceSopenharmony_cicallback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, 42d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 43d4afb5ceSopenharmony_ci{ 44d4afb5ceSopenharmony_ci const char *cp = (const char *)in; 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ci switch (reason) { 47d4afb5ceSopenharmony_ci 48d4afb5ceSopenharmony_ci /* callbacks related to file descriptor */ 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_ADOPT_FILE: 51d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_RAW_ADOPT_FILE\n"); 52d4afb5ceSopenharmony_ci break; 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_CLOSE_FILE: 55d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_RAW_CLOSE_FILE\n"); 56d4afb5ceSopenharmony_ci /* stdin close, wait 1s then close the raw skt */ 57d4afb5ceSopenharmony_ci stdin_wsi = NULL; /* invalid now we close */ 58d4afb5ceSopenharmony_ci if (raw_wsi) 59d4afb5ceSopenharmony_ci lws_set_timer_usecs(raw_wsi, us_wait_after_input_close); 60d4afb5ceSopenharmony_ci else { 61d4afb5ceSopenharmony_ci interrupted = 1; 62d4afb5ceSopenharmony_ci lws_cancel_service(context); 63d4afb5ceSopenharmony_ci } 64d4afb5ceSopenharmony_ci break; 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_RX_FILE: 67d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_RAW_RX_FILE\n"); 68d4afb5ceSopenharmony_ci waiting = (int)read(0, buf, sizeof(buf)); 69d4afb5ceSopenharmony_ci lwsl_notice("raw file read %d\n", waiting); 70d4afb5ceSopenharmony_ci if (waiting < 0) 71d4afb5ceSopenharmony_ci return -1; 72d4afb5ceSopenharmony_ci 73d4afb5ceSopenharmony_ci if (raw_wsi) 74d4afb5ceSopenharmony_ci lws_callback_on_writable(raw_wsi); 75d4afb5ceSopenharmony_ci lws_rx_flow_control(wsi, 0); 76d4afb5ceSopenharmony_ci break; 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_ci /* callbacks related to raw socket descriptor */ 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_ADOPT: 82d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_RAW_ADOPT\n"); 83d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 84d4afb5ceSopenharmony_ci break; 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_CLOSE: 87d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_RAW_CLOSE\n"); 88d4afb5ceSopenharmony_ci /* 89d4afb5ceSopenharmony_ci * If the socket to the remote server closed, we must close 90d4afb5ceSopenharmony_ci * and drop any remaining stdin 91d4afb5ceSopenharmony_ci */ 92d4afb5ceSopenharmony_ci interrupted = 1; 93d4afb5ceSopenharmony_ci lws_cancel_service(context); 94d4afb5ceSopenharmony_ci /* our pointer to this wsi is invalid now we close */ 95d4afb5ceSopenharmony_ci raw_wsi = NULL; 96d4afb5ceSopenharmony_ci break; 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_RX: 99d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len); 100d4afb5ceSopenharmony_ci while (len--) 101d4afb5ceSopenharmony_ci putchar(*cp++); 102d4afb5ceSopenharmony_ci fflush(stdout); 103d4afb5ceSopenharmony_ci break; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_WRITEABLE: 106d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_RAW_WRITEABLE\n"); 107d4afb5ceSopenharmony_ci // lwsl_hexdump_info(buf, waiting); 108d4afb5ceSopenharmony_ci if (stdin_wsi) 109d4afb5ceSopenharmony_ci lws_rx_flow_control(stdin_wsi, 1); 110d4afb5ceSopenharmony_ci if (lws_write(wsi, buf, (unsigned int)waiting, LWS_WRITE_RAW) != waiting) { 111d4afb5ceSopenharmony_ci lwsl_notice("%s: raw skt write failed\n", __func__); 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci return -1; 114d4afb5ceSopenharmony_ci } 115d4afb5ceSopenharmony_ci break; 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci case LWS_CALLBACK_TIMER: 118d4afb5ceSopenharmony_ci lwsl_user("LWS_CALLBACK_TIMER\n"); 119d4afb5ceSopenharmony_ci interrupted = 1; 120d4afb5ceSopenharmony_ci lws_cancel_service(context); 121d4afb5ceSopenharmony_ci return -1; 122d4afb5ceSopenharmony_ci 123d4afb5ceSopenharmony_ci default: 124d4afb5ceSopenharmony_ci break; 125d4afb5ceSopenharmony_ci } 126d4afb5ceSopenharmony_ci 127d4afb5ceSopenharmony_ci return 0; 128d4afb5ceSopenharmony_ci} 129d4afb5ceSopenharmony_ci 130d4afb5ceSopenharmony_cistatic struct lws_protocols protocols[] = { 131d4afb5ceSopenharmony_ci { "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 }, 132d4afb5ceSopenharmony_ci LWS_PROTOCOL_LIST_TERM 133d4afb5ceSopenharmony_ci}; 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_civoid sigint_handler(int sig) 136d4afb5ceSopenharmony_ci{ 137d4afb5ceSopenharmony_ci interrupted = 1; 138d4afb5ceSopenharmony_ci} 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ciint main(int argc, const char **argv) 141d4afb5ceSopenharmony_ci{ 142d4afb5ceSopenharmony_ci const char *server = "libwebsockets.org", *port = "80"; 143d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 144d4afb5ceSopenharmony_ci lws_sock_file_fd_type sock; 145d4afb5ceSopenharmony_ci struct addrinfo h, *r, *rp; 146d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 147d4afb5ceSopenharmony_ci const char *p; 148d4afb5ceSopenharmony_ci int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; 149d4afb5ceSopenharmony_ci 150d4afb5ceSopenharmony_ci signal(SIGINT, sigint_handler); 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-d"))) 153d4afb5ceSopenharmony_ci logs = atoi(p); 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci lws_set_log_level(logs, NULL); 156d4afb5ceSopenharmony_ci lwsl_user("LWS minimal raw netcat [--server ip] [--port port] [-w ms]\n"); 157d4afb5ceSopenharmony_ci 158d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 159d4afb5ceSopenharmony_ci info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS; 160d4afb5ceSopenharmony_ci 161d4afb5ceSopenharmony_ci context = lws_create_context(&info); 162d4afb5ceSopenharmony_ci if (!context) { 163d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 164d4afb5ceSopenharmony_ci return 1; 165d4afb5ceSopenharmony_ci } 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci info.port = CONTEXT_PORT_NO_LISTEN_SERVER; 168d4afb5ceSopenharmony_ci info.protocols = protocols; 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci vhost = lws_create_vhost(context, &info); 171d4afb5ceSopenharmony_ci if (!vhost) { 172d4afb5ceSopenharmony_ci lwsl_err("lws vhost creation failed\n"); 173d4afb5ceSopenharmony_ci goto bail; 174d4afb5ceSopenharmony_ci } 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci /* 177d4afb5ceSopenharmony_ci * Connect our own "foreign" socket to libwebsockets.org:80 178d4afb5ceSopenharmony_ci * 179d4afb5ceSopenharmony_ci * Normally you would do this with lws_client_connect_via_info() inside 180d4afb5ceSopenharmony_ci * the lws event loop, hiding all this detail. But this example 181d4afb5ceSopenharmony_ci * demonstrates how to integrate an externally-connected "foreign" 182d4afb5ceSopenharmony_ci * socket, so we create one by hand. 183d4afb5ceSopenharmony_ci */ 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci memset(&h, 0, sizeof(h)); 186d4afb5ceSopenharmony_ci h.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ 187d4afb5ceSopenharmony_ci h.ai_socktype = SOCK_STREAM; 188d4afb5ceSopenharmony_ci h.ai_protocol = IPPROTO_TCP; 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "--port"))) 191d4afb5ceSopenharmony_ci port = p; 192d4afb5ceSopenharmony_ci 193d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "--server"))) 194d4afb5ceSopenharmony_ci server = p; 195d4afb5ceSopenharmony_ci 196d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-w"))) 197d4afb5ceSopenharmony_ci us_wait_after_input_close = 1000 * atoi(p); 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci n = getaddrinfo(server, port, &h, &r); 200d4afb5ceSopenharmony_ci if (n) { 201d4afb5ceSopenharmony_ci lwsl_err("%s: problem resolving %s: %s\n", __func__, 202d4afb5ceSopenharmony_ci server, gai_strerror(n)); 203d4afb5ceSopenharmony_ci return 1; 204d4afb5ceSopenharmony_ci } 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci for (rp = r; rp; rp = rp->ai_next) { 207d4afb5ceSopenharmony_ci sock.sockfd = socket(rp->ai_family, rp->ai_socktype, 208d4afb5ceSopenharmony_ci rp->ai_protocol); 209d4afb5ceSopenharmony_ci if (sock.sockfd != LWS_SOCK_INVALID) 210d4afb5ceSopenharmony_ci break; 211d4afb5ceSopenharmony_ci } 212d4afb5ceSopenharmony_ci if (!rp) { 213d4afb5ceSopenharmony_ci lwsl_err("%s: unable to create INET socket\n", __func__); 214d4afb5ceSopenharmony_ci freeaddrinfo(r); 215d4afb5ceSopenharmony_ci 216d4afb5ceSopenharmony_ci return 1; 217d4afb5ceSopenharmony_ci } 218d4afb5ceSopenharmony_ci 219d4afb5ceSopenharmony_ci lwsl_user("Starting connect to %s:%s...\n", server, port); 220d4afb5ceSopenharmony_ci if (connect(sock.sockfd, rp->ai_addr, sizeof(*rp->ai_addr)) < 0) { 221d4afb5ceSopenharmony_ci lwsl_err("%s: unable to connect\n", __func__); 222d4afb5ceSopenharmony_ci freeaddrinfo(r); 223d4afb5ceSopenharmony_ci return 1; 224d4afb5ceSopenharmony_ci } 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci freeaddrinfo(r); 227d4afb5ceSopenharmony_ci signal(SIGINT, sigint_handler); 228d4afb5ceSopenharmony_ci lwsl_user("Connected...\n"); 229d4afb5ceSopenharmony_ci 230d4afb5ceSopenharmony_ci /* our foreign socket is connected... adopt it into lws */ 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_ci raw_wsi = lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_SOCKET, sock, 233d4afb5ceSopenharmony_ci protocols[0].name, NULL); 234d4afb5ceSopenharmony_ci if (!raw_wsi) { 235d4afb5ceSopenharmony_ci lwsl_err("%s: foreign socket adoption failed\n", __func__); 236d4afb5ceSopenharmony_ci goto bail; 237d4afb5ceSopenharmony_ci } 238d4afb5ceSopenharmony_ci 239d4afb5ceSopenharmony_ci sock.filefd = 0; 240d4afb5ceSopenharmony_ci stdin_wsi = lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_RAW_FILE_DESC, 241d4afb5ceSopenharmony_ci sock, protocols[0].name, NULL); 242d4afb5ceSopenharmony_ci if (!stdin_wsi) { 243d4afb5ceSopenharmony_ci lwsl_err("%s: stdin adoption failed\n", __func__); 244d4afb5ceSopenharmony_ci goto bail; 245d4afb5ceSopenharmony_ci } 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci while (n >= 0 && !interrupted) 248d4afb5ceSopenharmony_ci n = lws_service(context, 0); 249d4afb5ceSopenharmony_ci 250d4afb5ceSopenharmony_cibail: 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci lwsl_user("%s: destroying context\n", __func__); 253d4afb5ceSopenharmony_ci 254d4afb5ceSopenharmony_ci lws_context_destroy(context); 255d4afb5ceSopenharmony_ci 256d4afb5ceSopenharmony_ci return 0; 257d4afb5ceSopenharmony_ci} 258