2 * lws-minimal-raw-netcat
4 * Written in 2010-2019 by Andy Green <andy@warmcat.com>
6 * This file is made available under the Creative Commons CC0 1.0
7 * Universal Public Domain Dedication.
9 * This demonstrates sending stdin to a remote socket and printing
10 * what is returned to stdout.
12 * All the logging is on stderr, so you can tune it out with 2>log
16 #include <libwebsockets.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 #include <netinet/in.h>
24 #include <arpa/inet.h>
32 static struct lws *raw_wsi, *stdin_wsi;
33 static uint8_t buf[LWS_PRE + 4096];
34 static int waiting, interrupted;
35 static struct lws_context *context;
36 static int us_wait_after_input_close = LWS_USEC_PER_SEC / 10;
39 callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
40 void *user, void *in, size_t len)
42 const char *cp = (const char *)in;
46 /* callbacks related to file descriptor */
48 case LWS_CALLBACK_RAW_ADOPT_FILE:
49 lwsl_user("LWS_CALLBACK_RAW_ADOPT_FILE\n");
52 case LWS_CALLBACK_RAW_CLOSE_FILE:
53 lwsl_user("LWS_CALLBACK_RAW_CLOSE_FILE\n");
54 /* stdin close, wait 1s then close the raw skt */
55 stdin_wsi = NULL; /* invalid now we close */
57 lws_set_timer_usecs(raw_wsi, us_wait_after_input_close);
60 lws_cancel_service(context);
64 case LWS_CALLBACK_RAW_RX_FILE:
65 lwsl_user("LWS_CALLBACK_RAW_RX_FILE\n");
66 waiting = read(0, buf, sizeof(buf));
67 lwsl_notice("raw file read %d\n", waiting);
72 lws_callback_on_writable(raw_wsi);
73 lws_rx_flow_control(wsi, 0);
77 /* callbacks related to raw socket descriptor */
79 case LWS_CALLBACK_RAW_ADOPT:
80 lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
81 lws_callback_on_writable(wsi);
84 case LWS_CALLBACK_RAW_CLOSE:
85 lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
87 * If the socket to the remote server closed, we must close
88 * and drop any remaining stdin
91 lws_cancel_service(context);
92 /* our pointer to this wsi is invalid now we close */
96 case LWS_CALLBACK_RAW_RX:
97 lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
103 case LWS_CALLBACK_RAW_WRITEABLE:
104 lwsl_user("LWS_CALLBACK_RAW_WRITEABLE\n");
105 // lwsl_hexdump_info(buf, waiting);
107 lws_rx_flow_control(stdin_wsi, 1);
108 if (lws_write(wsi, buf, waiting, LWS_WRITE_RAW) != waiting) {
109 lwsl_notice("%s: raw skt write failed\n", __func__);
115 case LWS_CALLBACK_TIMER:
116 lwsl_user("LWS_CALLBACK_TIMER\n");
118 lws_cancel_service(context);
128 static struct lws_protocols protocols[] = {
129 { "raw-test", callback_raw_test, 0, 0 },
130 { NULL, NULL, 0, 0 } /* terminator */
133 void sigint_handler(int sig)
138 int main(int argc, const char **argv)
140 const char *server = "libwebsockets.org", *port = "80";
141 struct lws_context_creation_info info;
142 lws_sock_file_fd_type sock;
143 struct addrinfo h, *r, *rp;
144 struct lws_vhost *vhost;
146 int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
148 signal(SIGINT, sigint_handler);
150 if ((p = lws_cmdline_option(argc, argv, "-d")))
153 lws_set_log_level(logs, NULL);
154 lwsl_user("LWS minimal raw netcat [--server ip] [--port port] [-w ms]\n");
156 memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
157 info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
159 context = lws_create_context(&info);
161 lwsl_err("lws init failed\n");
165 info.port = CONTEXT_PORT_NO_LISTEN_SERVER;
166 info.protocols = protocols;
168 vhost = lws_create_vhost(context, &info);
170 lwsl_err("lws vhost creation failed\n");
175 * Connect our own "foreign" socket to libwebsockets.org:80
177 * Normally you would do this with lws_client_connect_via_info() inside
178 * the lws event loop, hiding all this detail. But this example
179 * demonstrates how to integrate an externally-connected "foreign"
180 * socket, so we create one by hand.
183 memset(&h, 0, sizeof(h));
184 h.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
185 h.ai_socktype = SOCK_STREAM;
186 h.ai_protocol = IPPROTO_TCP;
188 if ((p = lws_cmdline_option(argc, argv, "--port")))
191 if ((p = lws_cmdline_option(argc, argv, "--server")))
194 if ((p = lws_cmdline_option(argc, argv, "-w")))
195 us_wait_after_input_close = 1000 * atoi(p);
197 n = getaddrinfo(server, port, &h, &r);
199 lwsl_err("%s: problem resolving %s: %s\n", __func__,
200 server, gai_strerror(n));
204 for (rp = r; rp; rp = rp->ai_next) {
205 sock.sockfd = socket(rp->ai_family, rp->ai_socktype,
207 if (sock.sockfd != LWS_SOCK_INVALID)
211 lwsl_err("%s: unable to create INET socket\n", __func__);
217 lwsl_user("Starting connect to %s:%s...\n", server, port);
218 if (connect(sock.sockfd, rp->ai_addr, sizeof(*rp->ai_addr)) < 0) {
219 lwsl_err("%s: unable to connect\n", __func__);
225 signal(SIGINT, sigint_handler);
226 lwsl_user("Connected...\n");
228 /* our foreign socket is connected... adopt it into lws */
230 raw_wsi = lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_SOCKET, sock,
231 protocols[0].name, NULL);
233 lwsl_err("%s: foreign socket adoption failed\n", __func__);
238 stdin_wsi = lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_RAW_FILE_DESC,
239 sock, protocols[0].name, NULL);
241 lwsl_err("%s: stdin adoption failed\n", __func__);
245 while (n >= 0 && !interrupted)
246 n = lws_service(context, 0);
250 lwsl_user("%s: destroying context\n", __func__);
252 lws_context_destroy(context);