1/*
2 * ws protocol handler plugin for "dumb increment"
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 * 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.
15 *
16 * These test plugins are intended to be adapted for use in your code, which
17 * may be proprietary.  So unlike the library itself, they are licensed
18 * Public Domain.
19 *
20 * This is a copy of dumb_increment adapted slightly to serve as the
21 * "example-standalone-protocol", to show how to build protocol plugins
22 * outside the library easily.
23 */
24
25#if !defined (LWS_PLUGIN_STATIC)
26#if !defined(LWS_DLL)
27#define LWS_DLL
28#endif
29#if !defined(LWS_INTERNAL)
30#define LWS_INTERNAL
31#endif
32#include <libwebsockets.h>
33#endif
34
35#include <string.h>
36
37struct per_vhost_data__dumb_increment {
38	uv_timer_t timeout_watcher;
39	struct lws_context *context;
40	struct lws_vhost *vhost;
41	const struct lws_protocols *protocol;
42};
43
44struct per_session_data__dumb_increment {
45	int number;
46};
47
48static void
49uv_timeout_cb_dumb_increment(uv_timer_t *w
50#if UV_VERSION_MAJOR == 0
51		, int status
52#endif
53)
54{
55	struct per_vhost_data__dumb_increment *vhd = lws_container_of(w,
56			struct per_vhost_data__dumb_increment, timeout_watcher);
57	lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol);
58}
59
60static int
61callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
62			void *user, void *in, size_t len)
63{
64	struct per_session_data__dumb_increment *pss =
65			(struct per_session_data__dumb_increment *)user;
66	struct per_vhost_data__dumb_increment *vhd =
67			(struct per_vhost_data__dumb_increment *)
68			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
69					lws_get_protocol(wsi));
70	unsigned char buf[LWS_PRE + 512];
71	unsigned char *p = &buf[LWS_PRE];
72	int n, m;
73
74	switch (reason) {
75	case LWS_CALLBACK_PROTOCOL_INIT:
76		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
77				lws_get_protocol(wsi),
78				sizeof(struct per_vhost_data__dumb_increment));
79		vhd->context = lws_get_context(wsi);
80		vhd->protocol = lws_get_protocol(wsi);
81		vhd->vhost = lws_get_vhost(wsi);
82		uv_timer_init(lws_uv_getloop(vhd->context, 0),
83			      &vhd->timeout_watcher);
84		uv_timer_start(&vhd->timeout_watcher,
85			       uv_timeout_cb_dumb_increment, 50, 50);
86		break;
87
88	case LWS_CALLBACK_PROTOCOL_DESTROY:
89		if (!vhd)
90			break;
91		uv_timer_stop(&vhd->timeout_watcher);
92		break;
93
94	case LWS_CALLBACK_ESTABLISHED:
95		pss->number = 0;
96		break;
97
98	case LWS_CALLBACK_SERVER_WRITEABLE:
99		n = sprintf((char *)p, "%d", pss->number++);
100		m = lws_write(wsi, p, n, LWS_WRITE_TEXT);
101		if (m < n) {
102			lwsl_err("ERROR %d writing to di socket\n", n);
103			return -1;
104		}
105		break;
106
107	case LWS_CALLBACK_RECEIVE:
108		if (len < 6)
109			break;
110		if (strcmp((const char *)in, "reset\n") == 0)
111			pss->number = 0;
112		if (strcmp((const char *)in, "closeme\n") == 0) {
113			lwsl_notice("dumb_inc: closing as requested\n");
114			lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY,
115					 (unsigned char *)"seeya", 5);
116			return -1;
117		}
118		break;
119
120	default:
121		break;
122	}
123
124	return 0;
125}
126
127static const struct lws_protocols protocols[] = {
128	{
129		"example-standalone-protocol",
130		callback_dumb_increment,
131		sizeof(struct per_session_data__dumb_increment),
132		10, /* rx buf size must be >= permessage-deflate rx size */
133	},
134};
135
136LWS_VISIBLE const lws_plugin_protocol_t protocol_example_standalone = {
137	.hdr = {
138		"standalone",
139		"lws_protocol_plugin",
140		LWS_BUILD_HASH,
141		LWS_PLUGIN_API_MAGIC
142	},
143
144	.protocols = protocols,
145	.count_protocols = LWS_ARRAY_SIZE(protocols),
146	.extensions = NULL,
147	.count_extensions = 0,
148};
149