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