2 * libwebsockets-test-server - libwebsockets test implementation
4 * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
6 * This file is made available under the Creative Commons CC0 1.0
7 * Universal Public Domain Dedication.
9 * The person who associated a work with this deed has dedicated
10 * the work to the public domain by waiving all of his or her rights
11 * to the work worldwide under copyright law, including all related
12 * and neighboring rights, to the extent allowed by law. You can copy,
13 * modify, distribute and perform the work, even for commercial purposes,
14 * all without asking permission.
16 * The test apps are intended to be adapted for use in your code, which
17 * may be proprietary. So unlike the library itself, they are licensed
21 #if !defined (LWS_PLUGIN_STATIC)
24 #include "../lib/libwebsockets.h"
31 #include <gettimeofday.h>
42 struct per_session_data__lws_status {
43 struct per_session_data__lws_status *next;
49 struct per_session_data__lws_status *walk_next;
50 unsigned char subsequent:1;
51 unsigned char changed_partway:1;
54 struct per_vhost_data__lws_status {
55 struct per_session_data__lws_status *live_pss_list;
56 struct lws_context *context;
57 struct lws_vhost *vhost;
58 const struct lws_protocols *protocol;
63 trigger_resend(struct per_vhost_data__lws_status *vhd)
65 struct per_session_data__lws_status *pss = vhd->live_pss_list;
68 if (pss->walk == WALK_NONE) {
70 pss->walk_next = vhd->live_pss_list;
71 pss->walk = WALK_INITIAL;
73 pss->changed_partway = 1;
78 lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
81 /* lws-status protocol */
84 callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
85 void *user, void *in, size_t len)
87 struct per_session_data__lws_status *pss =
88 (struct per_session_data__lws_status *)user,
90 struct per_vhost_data__lws_status *vhd =
91 (struct per_vhost_data__lws_status *)
92 lws_protocol_vh_priv_get(lws_get_vhost(wsi),
93 lws_get_protocol(wsi));
94 char buf[LWS_PRE + 384], ip[24], *start = buf + LWS_PRE - 1, *p = start,
95 *end = buf + sizeof(buf) - 1;
100 case LWS_CALLBACK_PROTOCOL_INIT:
101 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
102 lws_get_protocol(wsi),
103 sizeof(struct per_vhost_data__lws_status));
104 vhd->context = lws_get_context(wsi);
105 vhd->protocol = lws_get_protocol(wsi);
106 vhd->vhost = lws_get_vhost(wsi);
109 case LWS_CALLBACK_ESTABLISHED:
112 * This shows how to stage sending a single ws message in
113 * multiple fragments. In this case, it lets us trade off
114 * memory needed to make the data vs time to send it.
117 vhd->count_live_pss++;
118 pss->next = vhd->live_pss_list;
119 vhd->live_pss_list = pss;
121 time(&pss->time_est);
123 strcpy(pss->user_agent, "unknown");
124 lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent),
125 WSI_TOKEN_HTTP_USER_AGENT);
129 case LWS_CALLBACK_SERVER_WRITEABLE:
132 n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;;
133 p += lws_snprintf(p, end - p,
134 "{ \"version\":\"%s\","
135 " \"hostname\":\"%s\","
136 " \"wsi\":\"%d\", \"conns\":[",
137 lws_get_library_version(),
138 lws_canonical_hostname(vhd->context),
139 vhd->count_live_pss);
140 pss->walk = WALK_LIST;
141 pss->walk_next = vhd->live_pss_list;
144 n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
153 pss2 = vhd->live_pss_list;
155 if (pss2 == pss->walk_next) {
162 /* our next guy went away */
163 pss->walk = WALK_FINAL;
164 pss->changed_partway = 1;
168 lws_get_peer_simple(pss->walk_next->wsi, ip, sizeof(ip));
169 p += lws_snprintf(p, end - p,
170 "{\"peer\":\"%s\",\"time\":\"%ld\","
172 ip, (unsigned long)pss->walk_next->time_est,
173 pss->walk_next->user_agent);
174 pss->walk_next = pss->walk_next->next;
176 pss->walk = WALK_FINAL;
180 n = LWS_WRITE_CONTINUATION;
181 p += sprintf(p, "]}");
182 if (pss->changed_partway) {
184 pss->walk_next = vhd->live_pss_list;
185 pss->walk = WALK_INITIAL;
187 pss->walk = WALK_NONE;
193 m = lws_write(wsi, (unsigned char *)start, p - start, n);
195 lwsl_err("ERROR %d writing to di socket\n", m);
199 if (pss->walk != WALK_NONE)
200 lws_callback_on_writable(wsi);
203 case LWS_CALLBACK_RECEIVE:
204 lwsl_notice("pmd test: RX len %d\n", (int)len);
208 case LWS_CALLBACK_CLOSED:
209 pss1 = vhd->live_pss_list;
215 pss2->next = pss->next;
217 vhd->live_pss_list = pss->next;
235 #define LWS_PLUGIN_PROTOCOL_LWS_STATUS \
238 callback_lws_status, \
239 sizeof(struct per_session_data__lws_status), \
240 512, /* rx buf size must be >= permessage-deflate rx size */ \
243 #if !defined (LWS_PLUGIN_STATIC)
245 static const struct lws_protocols protocols[] = {
246 LWS_PLUGIN_PROTOCOL_LWS_STATUS
250 LWS_EXTERN LWS_VISIBLE int
251 init_protocol_lws_status(struct lws_context *context,
252 struct lws_plugin_capability *c)
254 if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
255 lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
260 c->protocols = protocols;
261 c->count_protocols = ARRAY_SIZE(protocols);
262 c->extensions = NULL;
263 c->count_extensions = 0;
268 LWS_EXTERN LWS_VISIBLE int
269 destroy_protocol_lws_status(struct lws_context *context)