1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker * ws protocol handler plugin for "client_loopback_test"
3*1c60b9acSAndroid Build Coastguard Worker *
4*1c60b9acSAndroid Build Coastguard Worker * Written in 2010-2019 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker *
6*1c60b9acSAndroid Build Coastguard Worker * This file is made available under the Creative Commons CC0 1.0
7*1c60b9acSAndroid Build Coastguard Worker * Universal Public Domain Dedication.
8*1c60b9acSAndroid Build Coastguard Worker *
9*1c60b9acSAndroid Build Coastguard Worker * The person who associated a work with this deed has dedicated
10*1c60b9acSAndroid Build Coastguard Worker * the work to the public domain by waiving all of his or her rights
11*1c60b9acSAndroid Build Coastguard Worker * to the work worldwide under copyright law, including all related
12*1c60b9acSAndroid Build Coastguard Worker * and neighboring rights, to the extent allowed by law. You can copy,
13*1c60b9acSAndroid Build Coastguard Worker * modify, distribute and perform the work, even for commercial purposes,
14*1c60b9acSAndroid Build Coastguard Worker * all without asking permission.
15*1c60b9acSAndroid Build Coastguard Worker *
16*1c60b9acSAndroid Build Coastguard Worker * These test plugins are intended to be adapted for use in your code, which
17*1c60b9acSAndroid Build Coastguard Worker * may be proprietary. So unlike the library itself, they are licensed
18*1c60b9acSAndroid Build Coastguard Worker * Public Domain.
19*1c60b9acSAndroid Build Coastguard Worker */
20*1c60b9acSAndroid Build Coastguard Worker
21*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_DLL)
22*1c60b9acSAndroid Build Coastguard Worker #define LWS_DLL
23*1c60b9acSAndroid Build Coastguard Worker #endif
24*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_INTERNAL)
25*1c60b9acSAndroid Build Coastguard Worker #define LWS_INTERNAL
26*1c60b9acSAndroid Build Coastguard Worker #endif
27*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
28*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
29*1c60b9acSAndroid Build Coastguard Worker
30*1c60b9acSAndroid Build Coastguard Worker struct per_session_data__client_loopback_test {
31*1c60b9acSAndroid Build Coastguard Worker struct lws *wsi;
32*1c60b9acSAndroid Build Coastguard Worker };
33*1c60b9acSAndroid Build Coastguard Worker
34*1c60b9acSAndroid Build Coastguard Worker /*
35*1c60b9acSAndroid Build Coastguard Worker * This is a bit fiddly...
36*1c60b9acSAndroid Build Coastguard Worker *
37*1c60b9acSAndroid Build Coastguard Worker * 0) If you want the wss:// test to work, make sure the vhost is marked with
38*1c60b9acSAndroid Build Coastguard Worker * enable-client-ssl if using lwsws, or call lws_init_vhost_client_ssl() on
39*1c60b9acSAndroid Build Coastguard Worker * the vhost if you're doing it by hand.
40*1c60b9acSAndroid Build Coastguard Worker *
41*1c60b9acSAndroid Build Coastguard Worker * 1) enable the protocol on a vhost
42*1c60b9acSAndroid Build Coastguard Worker *
43*1c60b9acSAndroid Build Coastguard Worker * "ws-protocols": [{
44*1c60b9acSAndroid Build Coastguard Worker * "client-loopback-test": {
45*1c60b9acSAndroid Build Coastguard Worker * "status": "ok"
46*1c60b9acSAndroid Build Coastguard Worker * }, ...
47*1c60b9acSAndroid Build Coastguard Worker *
48*1c60b9acSAndroid Build Coastguard Worker * the vhost should listen on 80 (ws://) or 443 (wss://)
49*1c60b9acSAndroid Build Coastguard Worker *
50*1c60b9acSAndroid Build Coastguard Worker * 2) mount the http part of the test one level down on the same vhost, eg
51*1c60b9acSAndroid Build Coastguard Worker * {
52*1c60b9acSAndroid Build Coastguard Worker * "mountpoint": "/c",
53*1c60b9acSAndroid Build Coastguard Worker * "origin": "callback://client-loopback-test"
54*1c60b9acSAndroid Build Coastguard Worker * }
55*1c60b9acSAndroid Build Coastguard Worker *
56*1c60b9acSAndroid Build Coastguard Worker * 3) Use a browser to visit the mountpoint with a URI attached for looping
57*1c60b9acSAndroid Build Coastguard Worker * back, eg, if testing on localhost
58*1c60b9acSAndroid Build Coastguard Worker *
59*1c60b9acSAndroid Build Coastguard Worker * http://localhost/c/ws://localhost
60*1c60b9acSAndroid Build Coastguard Worker * https://localhost/c/wss://localhost
61*1c60b9acSAndroid Build Coastguard Worker *
62*1c60b9acSAndroid Build Coastguard Worker * 4) The HTTP part of this test protocol will try to do the requested
63*1c60b9acSAndroid Build Coastguard Worker * ws client connection, to the same test protocol on the same
64*1c60b9acSAndroid Build Coastguard Worker * server.
65*1c60b9acSAndroid Build Coastguard Worker */
66*1c60b9acSAndroid Build Coastguard Worker
67*1c60b9acSAndroid Build Coastguard Worker static int
callback_client_loopback_test(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)68*1c60b9acSAndroid Build Coastguard Worker callback_client_loopback_test(struct lws *wsi, enum lws_callback_reasons reason,
69*1c60b9acSAndroid Build Coastguard Worker void *user, void *in, size_t len)
70*1c60b9acSAndroid Build Coastguard Worker {
71*1c60b9acSAndroid Build Coastguard Worker struct lws_client_connect_info i;
72*1c60b9acSAndroid Build Coastguard Worker struct per_session_data__client_loopback_test *pss =
73*1c60b9acSAndroid Build Coastguard Worker (struct per_session_data__client_loopback_test *)user;
74*1c60b9acSAndroid Build Coastguard Worker const char *p = (const char *)in;
75*1c60b9acSAndroid Build Coastguard Worker char buf[100];
76*1c60b9acSAndroid Build Coastguard Worker int n;
77*1c60b9acSAndroid Build Coastguard Worker
78*1c60b9acSAndroid Build Coastguard Worker switch (reason) {
79*1c60b9acSAndroid Build Coastguard Worker
80*1c60b9acSAndroid Build Coastguard Worker /* HTTP part */
81*1c60b9acSAndroid Build Coastguard Worker
82*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_HTTP:
83*1c60b9acSAndroid Build Coastguard Worker if (len < 10)
84*1c60b9acSAndroid Build Coastguard Worker return -1;
85*1c60b9acSAndroid Build Coastguard Worker
86*1c60b9acSAndroid Build Coastguard Worker p++;
87*1c60b9acSAndroid Build Coastguard Worker while (*p && *p != '/')
88*1c60b9acSAndroid Build Coastguard Worker p++;
89*1c60b9acSAndroid Build Coastguard Worker if (!*p) {
90*1c60b9acSAndroid Build Coastguard Worker lws_return_http_status(wsi, 400, "Arg needs to be in format ws://xxx or wss://xxx");
91*1c60b9acSAndroid Build Coastguard Worker return -1;
92*1c60b9acSAndroid Build Coastguard Worker }
93*1c60b9acSAndroid Build Coastguard Worker p++;
94*1c60b9acSAndroid Build Coastguard Worker
95*1c60b9acSAndroid Build Coastguard Worker memset(&i, 0, sizeof(i));
96*1c60b9acSAndroid Build Coastguard Worker i.context = lws_get_context(wsi);
97*1c60b9acSAndroid Build Coastguard Worker
98*1c60b9acSAndroid Build Coastguard Worker // stacked /// get resolved to /
99*1c60b9acSAndroid Build Coastguard Worker
100*1c60b9acSAndroid Build Coastguard Worker if (strncmp(p, "ws:/", 4) == 0) {
101*1c60b9acSAndroid Build Coastguard Worker i.ssl_connection = 0;
102*1c60b9acSAndroid Build Coastguard Worker i.port = 80;
103*1c60b9acSAndroid Build Coastguard Worker p += 4;
104*1c60b9acSAndroid Build Coastguard Worker } else
105*1c60b9acSAndroid Build Coastguard Worker if (strncmp(p, "wss:/", 5) == 0) {
106*1c60b9acSAndroid Build Coastguard Worker i.port = 443;
107*1c60b9acSAndroid Build Coastguard Worker i.ssl_connection = 1;
108*1c60b9acSAndroid Build Coastguard Worker p += 5;
109*1c60b9acSAndroid Build Coastguard Worker } else {
110*1c60b9acSAndroid Build Coastguard Worker sprintf(buf, "Arg %s is not in format ws://xxx or wss://xxx\n", p);
111*1c60b9acSAndroid Build Coastguard Worker lws_return_http_status(wsi, 400, buf);
112*1c60b9acSAndroid Build Coastguard Worker return -1;
113*1c60b9acSAndroid Build Coastguard Worker }
114*1c60b9acSAndroid Build Coastguard Worker
115*1c60b9acSAndroid Build Coastguard Worker i.address = p;
116*1c60b9acSAndroid Build Coastguard Worker i.path = "";
117*1c60b9acSAndroid Build Coastguard Worker i.host = p;
118*1c60b9acSAndroid Build Coastguard Worker i.origin = p;
119*1c60b9acSAndroid Build Coastguard Worker i.ietf_version_or_minus_one = -1;
120*1c60b9acSAndroid Build Coastguard Worker i.protocol = "client-loopback-test";
121*1c60b9acSAndroid Build Coastguard Worker
122*1c60b9acSAndroid Build Coastguard Worker pss->wsi = lws_client_connect_via_info(&i);
123*1c60b9acSAndroid Build Coastguard Worker if (!pss->wsi)
124*1c60b9acSAndroid Build Coastguard Worker lws_return_http_status(wsi, 401, "client-loopback-test: connect failed\n");
125*1c60b9acSAndroid Build Coastguard Worker else {
126*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("client connection to %s:%d with ssl: %d started\n",
127*1c60b9acSAndroid Build Coastguard Worker i.address, i.port, i.ssl_connection);
128*1c60b9acSAndroid Build Coastguard Worker lws_return_http_status(wsi, 200, "OK");
129*1c60b9acSAndroid Build Coastguard Worker }
130*1c60b9acSAndroid Build Coastguard Worker
131*1c60b9acSAndroid Build Coastguard Worker /* either way, close the triggering http link */
132*1c60b9acSAndroid Build Coastguard Worker
133*1c60b9acSAndroid Build Coastguard Worker return -1;
134*1c60b9acSAndroid Build Coastguard Worker
135*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_CLOSED_HTTP:
136*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("Http part closed\n");
137*1c60b9acSAndroid Build Coastguard Worker break;
138*1c60b9acSAndroid Build Coastguard Worker
139*1c60b9acSAndroid Build Coastguard Worker /* server part */
140*1c60b9acSAndroid Build Coastguard Worker
141*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_ESTABLISHED:
142*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("server part: LWS_CALLBACK_ESTABLISHED\n");
143*1c60b9acSAndroid Build Coastguard Worker strcpy(buf + LWS_PRE, "Made it");
144*1c60b9acSAndroid Build Coastguard Worker n = lws_write(wsi, (unsigned char *)buf + LWS_PRE,
145*1c60b9acSAndroid Build Coastguard Worker 7, LWS_WRITE_TEXT);
146*1c60b9acSAndroid Build Coastguard Worker if (n < 7)
147*1c60b9acSAndroid Build Coastguard Worker return -1;
148*1c60b9acSAndroid Build Coastguard Worker break;
149*1c60b9acSAndroid Build Coastguard Worker
150*1c60b9acSAndroid Build Coastguard Worker /* client part */
151*1c60b9acSAndroid Build Coastguard Worker
152*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_CLIENT_ESTABLISHED:
153*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("Client connection established\n");
154*1c60b9acSAndroid Build Coastguard Worker break;
155*1c60b9acSAndroid Build Coastguard Worker
156*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_CLIENT_RECEIVE:
157*1c60b9acSAndroid Build Coastguard Worker lws_strncpy(buf, in, sizeof(buf));
158*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("Client connection received %ld from server '%s'\n",
159*1c60b9acSAndroid Build Coastguard Worker (long)len, buf);
160*1c60b9acSAndroid Build Coastguard Worker
161*1c60b9acSAndroid Build Coastguard Worker /* OK we are done with the client connection */
162*1c60b9acSAndroid Build Coastguard Worker return -1;
163*1c60b9acSAndroid Build Coastguard Worker
164*1c60b9acSAndroid Build Coastguard Worker default:
165*1c60b9acSAndroid Build Coastguard Worker break;
166*1c60b9acSAndroid Build Coastguard Worker }
167*1c60b9acSAndroid Build Coastguard Worker
168*1c60b9acSAndroid Build Coastguard Worker return 0;
169*1c60b9acSAndroid Build Coastguard Worker }
170*1c60b9acSAndroid Build Coastguard Worker
171*1c60b9acSAndroid Build Coastguard Worker LWS_VISIBLE const struct lws_protocols client_loopback_test_protocols[] = {
172*1c60b9acSAndroid Build Coastguard Worker {
173*1c60b9acSAndroid Build Coastguard Worker "client-loopback-test",
174*1c60b9acSAndroid Build Coastguard Worker callback_client_loopback_test,
175*1c60b9acSAndroid Build Coastguard Worker sizeof(struct per_session_data__client_loopback_test),
176*1c60b9acSAndroid Build Coastguard Worker 1024, /* rx buf size must be >= permessage-deflate rx size */
177*1c60b9acSAndroid Build Coastguard Worker 0, NULL, 0
178*1c60b9acSAndroid Build Coastguard Worker },
179*1c60b9acSAndroid Build Coastguard Worker };
180*1c60b9acSAndroid Build Coastguard Worker
181*1c60b9acSAndroid Build Coastguard Worker LWS_VISIBLE const lws_plugin_protocol_t client_loopback_test = {
182*1c60b9acSAndroid Build Coastguard Worker .hdr = {
183*1c60b9acSAndroid Build Coastguard Worker "client loopback test",
184*1c60b9acSAndroid Build Coastguard Worker "lws_protocol_plugin",
185*1c60b9acSAndroid Build Coastguard Worker LWS_BUILD_HASH,
186*1c60b9acSAndroid Build Coastguard Worker LWS_PLUGIN_API_MAGIC
187*1c60b9acSAndroid Build Coastguard Worker },
188*1c60b9acSAndroid Build Coastguard Worker
189*1c60b9acSAndroid Build Coastguard Worker .protocols = client_loopback_test_protocols,
190*1c60b9acSAndroid Build Coastguard Worker .count_protocols = LWS_ARRAY_SIZE(client_loopback_test_protocols),
191*1c60b9acSAndroid Build Coastguard Worker .extensions = NULL,
192*1c60b9acSAndroid Build Coastguard Worker .count_extensions = 0,
193*1c60b9acSAndroid Build Coastguard Worker };
194