1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets-test-server - libwebsockets test implementation 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 * The test apps 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_PLUGIN_STATIC) 22d4afb5ceSopenharmony_ci#if !defined(LWS_DLL) 23d4afb5ceSopenharmony_ci#define LWS_DLL 24d4afb5ceSopenharmony_ci#endif 25d4afb5ceSopenharmony_ci#if !defined(LWS_INTERNAL) 26d4afb5ceSopenharmony_ci#define LWS_INTERNAL 27d4afb5ceSopenharmony_ci#endif 28d4afb5ceSopenharmony_ci#include <libwebsockets.h> 29d4afb5ceSopenharmony_ci#endif 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci#include <time.h> 32d4afb5ceSopenharmony_ci#include <string.h> 33d4afb5ceSopenharmony_ci#ifdef WIN32 34d4afb5ceSopenharmony_ci#include <io.h> 35d4afb5ceSopenharmony_ci#include <gettimeofday.h> 36d4afb5ceSopenharmony_ci#endif 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_citypedef enum { 40d4afb5ceSopenharmony_ci WALK_NONE, 41d4afb5ceSopenharmony_ci WALK_INITIAL, 42d4afb5ceSopenharmony_ci WALK_LIST, 43d4afb5ceSopenharmony_ci WALK_FINAL 44d4afb5ceSopenharmony_ci} e_walk; 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_cistruct per_session_data__lws_status { 47d4afb5ceSopenharmony_ci struct per_session_data__lws_status *next; 48d4afb5ceSopenharmony_ci struct lws *wsi; 49d4afb5ceSopenharmony_ci time_t time_est; 50d4afb5ceSopenharmony_ci char user_agent[256]; 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_ci e_walk walk; 53d4afb5ceSopenharmony_ci struct per_session_data__lws_status *walk_next; 54d4afb5ceSopenharmony_ci unsigned char subsequent:1; 55d4afb5ceSopenharmony_ci unsigned char changed_partway:1; 56d4afb5ceSopenharmony_ci unsigned char wss_over_h2:1; 57d4afb5ceSopenharmony_ci}; 58d4afb5ceSopenharmony_ci 59d4afb5ceSopenharmony_cistruct per_vhost_data__lws_status { 60d4afb5ceSopenharmony_ci struct per_session_data__lws_status *live_pss_list; 61d4afb5ceSopenharmony_ci struct lws_context *context; 62d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 63d4afb5ceSopenharmony_ci const struct lws_protocols *protocol; 64d4afb5ceSopenharmony_ci int count_live_pss; 65d4afb5ceSopenharmony_ci}; 66d4afb5ceSopenharmony_ci 67d4afb5ceSopenharmony_cistatic void 68d4afb5ceSopenharmony_citrigger_resend(struct per_vhost_data__lws_status *vhd) 69d4afb5ceSopenharmony_ci{ 70d4afb5ceSopenharmony_ci lws_start_foreach_ll(struct per_session_data__lws_status *, pss, 71d4afb5ceSopenharmony_ci vhd->live_pss_list) { 72d4afb5ceSopenharmony_ci if (pss->walk == WALK_NONE) { 73d4afb5ceSopenharmony_ci pss->subsequent = 0; 74d4afb5ceSopenharmony_ci pss->walk_next = vhd->live_pss_list; 75d4afb5ceSopenharmony_ci pss->walk = WALK_INITIAL; 76d4afb5ceSopenharmony_ci } else 77d4afb5ceSopenharmony_ci pss->changed_partway = 1; 78d4afb5ceSopenharmony_ci } lws_end_foreach_ll(pss, next); 79d4afb5ceSopenharmony_ci 80d4afb5ceSopenharmony_ci lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol); 81d4afb5ceSopenharmony_ci} 82d4afb5ceSopenharmony_ci 83d4afb5ceSopenharmony_ci/* lws-status protocol */ 84d4afb5ceSopenharmony_ci 85d4afb5ceSopenharmony_ciint 86d4afb5ceSopenharmony_cicallback_lws_status(struct lws *wsi, enum lws_callback_reasons reason, 87d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 88d4afb5ceSopenharmony_ci{ 89d4afb5ceSopenharmony_ci struct per_session_data__lws_status *pss = 90d4afb5ceSopenharmony_ci (struct per_session_data__lws_status *)user; 91d4afb5ceSopenharmony_ci struct per_vhost_data__lws_status *vhd = 92d4afb5ceSopenharmony_ci (struct per_vhost_data__lws_status *) 93d4afb5ceSopenharmony_ci lws_protocol_vh_priv_get(lws_get_vhost(wsi), 94d4afb5ceSopenharmony_ci lws_get_protocol(wsi)); 95d4afb5ceSopenharmony_ci char buf[LWS_PRE + 384], ip[24], *start = buf + LWS_PRE - 1, *p = start, 96d4afb5ceSopenharmony_ci *end = buf + sizeof(buf) - 1; 97d4afb5ceSopenharmony_ci int n, m; 98d4afb5ceSopenharmony_ci 99d4afb5ceSopenharmony_ci switch (reason) { 100d4afb5ceSopenharmony_ci 101d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_INIT: 102d4afb5ceSopenharmony_ci vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), 103d4afb5ceSopenharmony_ci lws_get_protocol(wsi), 104d4afb5ceSopenharmony_ci sizeof(struct per_vhost_data__lws_status)); 105d4afb5ceSopenharmony_ci if (!vhd) { 106d4afb5ceSopenharmony_ci lwsl_notice("%s: PROTOCOL_INIT failed\n", __func__); 107d4afb5ceSopenharmony_ci return 0; 108d4afb5ceSopenharmony_ci } 109d4afb5ceSopenharmony_ci vhd->context = lws_get_context(wsi); 110d4afb5ceSopenharmony_ci vhd->protocol = lws_get_protocol(wsi); 111d4afb5ceSopenharmony_ci vhd->vhost = lws_get_vhost(wsi); 112d4afb5ceSopenharmony_ci break; 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci case LWS_CALLBACK_ESTABLISHED: 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci /* 117d4afb5ceSopenharmony_ci * This shows how to stage sending a single ws message in 118d4afb5ceSopenharmony_ci * multiple fragments. In this case, it lets us trade off 119d4afb5ceSopenharmony_ci * memory needed to make the data vs time to send it. 120d4afb5ceSopenharmony_ci */ 121d4afb5ceSopenharmony_ci 122d4afb5ceSopenharmony_ci vhd->count_live_pss++; 123d4afb5ceSopenharmony_ci pss->next = vhd->live_pss_list; 124d4afb5ceSopenharmony_ci vhd->live_pss_list = pss; 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ci pss->wss_over_h2 = !!len; 127d4afb5ceSopenharmony_ci 128d4afb5ceSopenharmony_ci time(&pss->time_est); 129d4afb5ceSopenharmony_ci pss->wsi = wsi; 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 132d4afb5ceSopenharmony_ci if (lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent), 133d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_USER_AGENT) < 0) /* too big */ 134d4afb5ceSopenharmony_ci#endif 135d4afb5ceSopenharmony_ci strcpy(pss->user_agent, "unknown"); 136d4afb5ceSopenharmony_ci trigger_resend(vhd); 137d4afb5ceSopenharmony_ci break; 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_ci case LWS_CALLBACK_SERVER_WRITEABLE: 140d4afb5ceSopenharmony_ci switch (pss->walk) { 141d4afb5ceSopenharmony_ci case WALK_INITIAL: 142d4afb5ceSopenharmony_ci n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN; 143d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 144d4afb5ceSopenharmony_ci "{ \"version\":\"%s\"," 145d4afb5ceSopenharmony_ci " \"wss_over_h2\":\"%d\"," 146d4afb5ceSopenharmony_ci " \"hostname\":\"%s\"," 147d4afb5ceSopenharmony_ci " \"wsi\":\"%d\", \"conns\":[", 148d4afb5ceSopenharmony_ci lws_get_library_version(), 149d4afb5ceSopenharmony_ci pss->wss_over_h2, 150d4afb5ceSopenharmony_ci lws_canonical_hostname(vhd->context), 151d4afb5ceSopenharmony_ci vhd->count_live_pss); 152d4afb5ceSopenharmony_ci pss->walk = WALK_LIST; 153d4afb5ceSopenharmony_ci pss->walk_next = vhd->live_pss_list; 154d4afb5ceSopenharmony_ci break; 155d4afb5ceSopenharmony_ci case WALK_LIST: 156d4afb5ceSopenharmony_ci n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN; 157d4afb5ceSopenharmony_ci if (!pss->walk_next) 158d4afb5ceSopenharmony_ci goto walk_final; 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci if (pss->subsequent) 161d4afb5ceSopenharmony_ci *p++ = ','; 162d4afb5ceSopenharmony_ci pss->subsequent = 1; 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci m = 0; 165d4afb5ceSopenharmony_ci lws_start_foreach_ll(struct per_session_data__lws_status *, 166d4afb5ceSopenharmony_ci pss2, vhd->live_pss_list) { 167d4afb5ceSopenharmony_ci if (pss2 == pss->walk_next) { 168d4afb5ceSopenharmony_ci m = 1; 169d4afb5ceSopenharmony_ci break; 170d4afb5ceSopenharmony_ci } 171d4afb5ceSopenharmony_ci } lws_end_foreach_ll(pss2, next); 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci if (!m) { 174d4afb5ceSopenharmony_ci /* our next guy went away */ 175d4afb5ceSopenharmony_ci pss->walk = WALK_FINAL; 176d4afb5ceSopenharmony_ci pss->changed_partway = 1; 177d4afb5ceSopenharmony_ci break; 178d4afb5ceSopenharmony_ci } 179d4afb5ceSopenharmony_ci 180d4afb5ceSopenharmony_ci strcpy(ip, "unknown"); 181d4afb5ceSopenharmony_ci lws_get_peer_simple(pss->walk_next->wsi, ip, sizeof(ip)); 182d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 183d4afb5ceSopenharmony_ci "{\"peer\":\"%s\",\"time\":\"%ld\"," 184d4afb5ceSopenharmony_ci "\"ua\":\"%s\"}", 185d4afb5ceSopenharmony_ci ip, (unsigned long)pss->walk_next->time_est, 186d4afb5ceSopenharmony_ci pss->walk_next->user_agent); 187d4afb5ceSopenharmony_ci pss->walk_next = pss->walk_next->next; 188d4afb5ceSopenharmony_ci if (!pss->walk_next) 189d4afb5ceSopenharmony_ci pss->walk = WALK_FINAL; 190d4afb5ceSopenharmony_ci break; 191d4afb5ceSopenharmony_ci case WALK_FINAL: 192d4afb5ceSopenharmony_ciwalk_final: 193d4afb5ceSopenharmony_ci n = LWS_WRITE_CONTINUATION; 194d4afb5ceSopenharmony_ci p += lws_snprintf(p, 4, "]}"); 195d4afb5ceSopenharmony_ci if (pss->changed_partway) { 196d4afb5ceSopenharmony_ci pss->changed_partway = 0; 197d4afb5ceSopenharmony_ci pss->subsequent = 0; 198d4afb5ceSopenharmony_ci pss->walk_next = vhd->live_pss_list; 199d4afb5ceSopenharmony_ci pss->walk = WALK_INITIAL; 200d4afb5ceSopenharmony_ci } else 201d4afb5ceSopenharmony_ci pss->walk = WALK_NONE; 202d4afb5ceSopenharmony_ci break; 203d4afb5ceSopenharmony_ci default: 204d4afb5ceSopenharmony_ci return 0; 205d4afb5ceSopenharmony_ci } 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_ci m = lws_write(wsi, (unsigned char *)start, lws_ptr_diff_size_t(p, start), (unsigned int)n); 208d4afb5ceSopenharmony_ci if (m < 0) { 209d4afb5ceSopenharmony_ci lwsl_err("ERROR %d writing to di socket\n", m); 210d4afb5ceSopenharmony_ci return -1; 211d4afb5ceSopenharmony_ci } 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ci if (pss->walk != WALK_NONE) 214d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 215d4afb5ceSopenharmony_ci break; 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE: 218d4afb5ceSopenharmony_ci lwsl_notice("pmd test: RX len %d\n", (int)len); 219d4afb5ceSopenharmony_ci break; 220d4afb5ceSopenharmony_ci 221d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED: 222d4afb5ceSopenharmony_ci // lwsl_debug("****** LWS_CALLBACK_CLOSED\n"); 223d4afb5ceSopenharmony_ci lws_start_foreach_llp(struct per_session_data__lws_status **, 224d4afb5ceSopenharmony_ci ppss, vhd->live_pss_list) { 225d4afb5ceSopenharmony_ci if (*ppss == pss) { 226d4afb5ceSopenharmony_ci *ppss = pss->next; 227d4afb5ceSopenharmony_ci break; 228d4afb5ceSopenharmony_ci } 229d4afb5ceSopenharmony_ci } lws_end_foreach_llp(ppss, next); 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci trigger_resend(vhd); 232d4afb5ceSopenharmony_ci break; 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_ci default: 235d4afb5ceSopenharmony_ci break; 236d4afb5ceSopenharmony_ci } 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci return 0; 239d4afb5ceSopenharmony_ci} 240d4afb5ceSopenharmony_ci 241d4afb5ceSopenharmony_ci#define LWS_PLUGIN_PROTOCOL_LWS_STATUS \ 242d4afb5ceSopenharmony_ci { \ 243d4afb5ceSopenharmony_ci "lws-status", \ 244d4afb5ceSopenharmony_ci callback_lws_status, \ 245d4afb5ceSopenharmony_ci sizeof(struct per_session_data__lws_status), \ 246d4afb5ceSopenharmony_ci 512, /* rx buf size must be >= permessage-deflate rx size */ \ 247d4afb5ceSopenharmony_ci 0, NULL, 0 \ 248d4afb5ceSopenharmony_ci } 249d4afb5ceSopenharmony_ci 250d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC) 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ciLWS_VISIBLE const struct lws_protocols lws_status_protocols[] = { 253d4afb5ceSopenharmony_ci LWS_PLUGIN_PROTOCOL_LWS_STATUS 254d4afb5ceSopenharmony_ci}; 255d4afb5ceSopenharmony_ci 256d4afb5ceSopenharmony_ciLWS_VISIBLE const lws_plugin_protocol_t lws_status = { 257d4afb5ceSopenharmony_ci .hdr = { 258d4afb5ceSopenharmony_ci "lws status", 259d4afb5ceSopenharmony_ci "lws_protocol_plugin", 260d4afb5ceSopenharmony_ci LWS_BUILD_HASH, 261d4afb5ceSopenharmony_ci LWS_PLUGIN_API_MAGIC 262d4afb5ceSopenharmony_ci }, 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci .protocols = lws_status_protocols, 265d4afb5ceSopenharmony_ci .count_protocols = LWS_ARRAY_SIZE(lws_status_protocols), 266d4afb5ceSopenharmony_ci .extensions = NULL, 267d4afb5ceSopenharmony_ci .count_extensions = 0, 268d4afb5ceSopenharmony_ci}; 269d4afb5ceSopenharmony_ci 270d4afb5ceSopenharmony_ci#endif 271