• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-minimal-ws-client
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 the a minimal ws client using lws.
10  *
11  * It connects to https://libwebsockets.org/ and makes a
12  * wss connection to the dumb-increment protocol there.  While
13  * connected, it prints the numbers it is being sent by
14  * dumb-increment protocol.
15  */
16 
17 #include <libwebsockets.h>
18 #include <string.h>
19 #include <signal.h>
20 
21 static int interrupted, rx_seen, test;
22 static struct lws *client_wsi;
23 
24 static int
callback_dumb_increment(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)25 callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
26 	      void *user, void *in, size_t len)
27 {
28 	switch (reason) {
29 
30 	/* because we are protocols[0] ... */
31 	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
32 		lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
33 			 in ? (char *)in : "(null)");
34 		client_wsi = NULL;
35 		break;
36 
37 	case LWS_CALLBACK_CLIENT_ESTABLISHED:
38 		lwsl_user("%s: established\n", __func__);
39 		break;
40 
41 	case LWS_CALLBACK_CLIENT_RECEIVE:
42 		lwsl_user("RX: %s\n", (const char *)in);
43 		rx_seen++;
44 		if (test && rx_seen == 10)
45 			interrupted = 1;
46 		break;
47 
48 	case LWS_CALLBACK_CLIENT_CLOSED:
49 		client_wsi = NULL;
50 		break;
51 
52 	default:
53 		break;
54 	}
55 
56 	return lws_callback_http_dummy(wsi, reason, user, in, len);
57 }
58 
59 static const struct lws_protocols protocols[] = {
60 	{
61 		"dumb-increment-protocol",
62 		callback_dumb_increment,
63 		0, 0, 0, NULL, 0
64 	},
65 	LWS_PROTOCOL_LIST_TERM
66 };
67 
68 static void
sigint_handler(int sig)69 sigint_handler(int sig)
70 {
71 	interrupted = 1;
72 }
73 
main(int argc,const char ** argv)74 int main(int argc, const char **argv)
75 {
76 	struct lws_context_creation_info info;
77 	struct lws_client_connect_info i;
78 	struct lws_context *context;
79 	const char *p;
80 	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
81 		/* for LLL_ verbosity above NOTICE to be built into lws, lws
82 		 * must have been configured with -DCMAKE_BUILD_TYPE=DEBUG
83 		 * instead of =RELEASE */
84 		/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
85 		/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
86 		/* | LLL_DEBUG */;
87 
88 	signal(SIGINT, sigint_handler);
89 	if ((p = lws_cmdline_option(argc, argv, "-d")))
90 		logs = atoi(p);
91 
92 	test = !!lws_cmdline_option(argc, argv, "-t");
93 
94 	lws_set_log_level(logs, NULL);
95 	lwsl_user("LWS minimal ws client rx [-d <logs>] [--h2] [-t (test)]\n");
96 
97 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
98 	info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
99 	info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
100 	info.protocols = protocols;
101 	info.timeout_secs = 10;
102 	info.connect_timeout_secs = 30;
103 #if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
104 	/*
105 	 * OpenSSL uses the system trust store.  mbedTLS has to be told which
106 	 * CA to trust explicitly.
107 	 */
108 	info.client_ssl_ca_filepath = "./libwebsockets.org.cer";
109 #endif
110 
111 	/*
112 	 * since we know this lws context is only ever going to be used with
113 	 * one client wsis / fds / sockets at a time, let lws know it doesn't
114 	 * have to use the default allocations for fd tables up to ulimit -n.
115 	 * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
116 	 * will use.
117 	 */
118 	info.fd_limit_per_thread = 1 + 1 + 1;
119 
120 	context = lws_create_context(&info);
121 	if (!context) {
122 		lwsl_err("lws init failed\n");
123 		return 1;
124 	}
125 
126 	memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
127 	i.context = context;
128 	i.port = 443;
129 	i.address = "libwebsockets.org";
130 	i.path = "/";
131 	i.host = i.address;
132 	i.origin = i.address;
133 	i.ssl_connection = LCCSCF_USE_SSL;
134 	i.protocol = protocols[0].name; /* "dumb-increment-protocol" */
135 	i.pwsi = &client_wsi;
136 
137 	if (lws_cmdline_option(argc, argv, "--h2"))
138 		i.alpn = "h2";
139 
140 	lws_client_connect_via_info(&i);
141 
142 	while (n >= 0 && client_wsi && !interrupted)
143 		n = lws_service(context, 0);
144 
145 	lws_context_destroy(context);
146 
147 	lwsl_user("Completed %s\n", rx_seen > 10 ? "OK" : "Failed");
148 
149 	return rx_seen > 10;
150 }
151