1 /*
2  * lws-minimal-ws-client-echo
3  *
4  * Written in 2010-2019 by Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  *
9  * This demonstrates a ws client that echoes back what it was sent, in a
10  * way compatible with autobahn -m fuzzingserver
11  */
12 
13 #include <libwebsockets.h>
14 #include <string.h>
15 #include <signal.h>
16 
17 #define LWS_PLUGIN_STATIC
18 #include "protocol_lws_minimal_client_echo.c"
19 
20 static struct lws_protocols protocols[] = {
21 	LWS_PLUGIN_PROTOCOL_MINIMAL_CLIENT_ECHO,
22 	{ NULL, NULL, 0, 0 } /* terminator */
23 };
24 
25 static struct lws_context *context;
26 static int interrupted, port = 7681, options = 0;
27 static const char *url = "/", *ads = "localhost", *iface = NULL;
28 
29 /* pass pointers to shared vars to the protocol */
30 
31 static const struct lws_protocol_vhost_options pvo_iface = {
32 	NULL,
33 	NULL,
34 	"iface",		/* pvo name */
35 	(void *)&iface	/* pvo value */
36 };
37 
38 static const struct lws_protocol_vhost_options pvo_ads = {
39 	&pvo_iface,
40 	NULL,
41 	"ads",		/* pvo name */
42 	(void *)&ads	/* pvo value */
43 };
44 
45 static const struct lws_protocol_vhost_options pvo_url = {
46 	&pvo_ads,
47 	NULL,
48 	"url",		/* pvo name */
49 	(void *)&url	/* pvo value */
50 };
51 
52 static const struct lws_protocol_vhost_options pvo_options = {
53 	&pvo_url,
54 	NULL,
55 	"options",		/* pvo name */
56 	(void *)&options	/* pvo value */
57 };
58 
59 static const struct lws_protocol_vhost_options pvo_port = {
60 	&pvo_options,
61 	NULL,
62 	"port",		/* pvo name */
63 	(void *)&port	/* pvo value */
64 };
65 
66 static const struct lws_protocol_vhost_options pvo_interrupted = {
67 	&pvo_port,
68 	NULL,
69 	"interrupted",		/* pvo name */
70 	(void *)&interrupted	/* pvo value */
71 };
72 
73 static const struct lws_protocol_vhost_options pvo = {
74 	NULL,		/* "next" pvo linked-list */
75 	&pvo_interrupted,	/* "child" pvo linked-list */
76 	"lws-minimal-client-echo",	/* protocol name we belong to on this vhost */
77 	""		/* ignored */
78 };
79 static const struct lws_extension extensions[] = {
80 	{
81 		"permessage-deflate",
82 		lws_extension_callback_pm_deflate,
83 		"permessage-deflate"
84 		 "; client_no_context_takeover"
85 		 "; client_max_window_bits"
86 	},
87 	{ NULL, NULL, NULL /* terminator */ }
88 };
89 
sigint_handler(int sig)90 void sigint_handler(int sig)
91 {
92 	interrupted = 1;
93 }
94 
main(int argc,const char ** argv)95 int main(int argc, const char **argv)
96 {
97 	struct lws_context_creation_info info;
98 	const char *p;
99 	int n, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
100 			/* for LLL_ verbosity above NOTICE to be built into lws,
101 			 * lws must have been configured and built with
102 			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
103 			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
104 			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
105 			/* | LLL_DEBUG */;
106 
107 	if ((p = lws_cmdline_option(argc, argv, "-d")))
108 		logs = atoi(p);
109 
110 	lws_set_log_level(logs, NULL);
111 	lwsl_user("LWS minimal ws client echo + permessage-deflate + multifragment bulk message\n");
112 	lwsl_user("   lws-minimal-ws-client-echo [-n (no exts)] [-u url] [-p port] [-o (once)]\n");
113 
114 	if ((p = lws_cmdline_option(argc, argv, "-u")))
115 		url = p;
116 
117 	if ((p = lws_cmdline_option(argc, argv, "-p")))
118 		port = atoi(p);
119 
120 	if (lws_cmdline_option(argc, argv, "-o"))
121 		options |= 1;
122 
123 	if (lws_cmdline_option(argc, argv, "--ssl"))
124 		options |= 2;
125 
126 	if ((p = lws_cmdline_option(argc, argv, "-s")))
127 		ads = p;
128 
129 	if ((p = lws_cmdline_option(argc, argv, "-i")))
130 		iface = p;
131 
132 	lwsl_user("options %d, ads %s\n", options, ads);
133 
134 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
135 	info.port = CONTEXT_PORT_NO_LISTEN;
136 	info.protocols = protocols;
137 	info.pvo = &pvo;
138 	if (!lws_cmdline_option(argc, argv, "-n"))
139 		info.extensions = extensions;
140 	info.pt_serv_buf_size = 32 * 1024;
141 	info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
142 		       LWS_SERVER_OPTION_VALIDATE_UTF8;
143 	/*
144 	 * since we know this lws context is only ever going to be used with
145 	 * one client wsis / fds / sockets at a time, let lws know it doesn't
146 	 * have to use the default allocations for fd tables up to ulimit -n.
147 	 * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
148 	 * will use.
149 	 */
150 	info.fd_limit_per_thread = 1 + 1 + 1;
151 
152 	if (lws_cmdline_option(argc, argv, "--libuv"))
153 		info.options |= LWS_SERVER_OPTION_LIBUV;
154 	else
155 		signal(SIGINT, sigint_handler);
156 
157 	context = lws_create_context(&info);
158 	if (!context) {
159 		lwsl_err("lws init failed\n");
160 		return 1;
161 	}
162 
163 	while (!lws_service(context, 0) && !interrupted)
164 		;
165 
166 	lws_context_destroy(context);
167 
168 	n = (options & 1) ? interrupted != 2 : interrupted == 3;
169 	lwsl_user("Completed %d %s\n", interrupted, !n ? "OK" : "failed");
170 
171 	return n;
172 }
173