1 /*
2 * lws-minimal-raw-vhost
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 * This demonstrates integrating a raw tcp listener into the lws event loop.
10 *
11 * This demo doesn't have any http or ws support. You can connect to it
12 * using netcat. If you make multiple connections to it, things typed in one
13 * netcat session are broadcast to all netcat connections.
14 *
15 * $ nc localhost 7681
16 *
17 * You can add more vhosts with things like http or ws support, it's as it is
18 * for clarity.
19 *
20 * The main point is the apis and ways of managing raw sockets are almost
21 * identical to http or ws mode sockets in lws. The callback names for raw
22 * wsi are changed to be specific to RAW mode is all.
23 */
24
25 #include <libwebsockets.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31
32 struct raw_pss {
33 struct raw_pss *pss_list;
34 struct lws *wsi;
35 };
36
37 /* one of these is created for each vhost our protocol is used with */
38
39 struct raw_vhd {
40 struct raw_pss *pss_list; /* linked-list of live pss*/
41
42 int len;
43 uint8_t buf[4096];
44 };
45
46 static int
callback_raw_test(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)47 callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
48 void *user, void *in, size_t len)
49 {
50 struct raw_pss *pss = (struct raw_pss *)user;
51 struct raw_vhd *vhd = (struct raw_vhd *)lws_protocol_vh_priv_get(
52 lws_get_vhost(wsi), lws_get_protocol(wsi));
53
54 switch (reason) {
55 case LWS_CALLBACK_PROTOCOL_INIT:
56 lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
57 lws_get_protocol(wsi), sizeof(struct raw_vhd));
58 break;
59
60 case LWS_CALLBACK_PROTOCOL_DESTROY:
61 break;
62
63 /* callbacks related to raw socket descriptor */
64
65 case LWS_CALLBACK_RAW_ADOPT:
66 lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
67 pss->wsi = wsi;
68 lws_ll_fwd_insert(pss, pss_list, vhd->pss_list);
69 break;
70
71 case LWS_CALLBACK_RAW_CLOSE:
72 lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
73 lws_ll_fwd_remove(struct raw_pss, pss_list, pss, vhd->pss_list);
74 break;
75
76 case LWS_CALLBACK_RAW_RX:
77 lwsl_user("LWS_CALLBACK_RAW_RX: %d\n", (int)len);
78 vhd->len = (int)len;
79 if (vhd->len > (int)sizeof(vhd->buf))
80 vhd->len = sizeof(vhd->buf);
81 memcpy(vhd->buf, in, (unsigned int)vhd->len);
82 lws_start_foreach_llp(struct raw_pss **, ppss, vhd->pss_list) {
83 lws_callback_on_writable((*ppss)->wsi);
84 } lws_end_foreach_llp(ppss, pss_list);
85 break;
86
87 case LWS_CALLBACK_RAW_WRITEABLE:
88 if (lws_write(wsi, vhd->buf, (unsigned int)vhd->len, LWS_WRITE_RAW) !=
89 vhd->len) {
90 lwsl_notice("%s: raw write failed\n", __func__);
91 return 1;
92 }
93 break;
94
95 default:
96 break;
97 }
98
99 return lws_callback_http_dummy(wsi, reason, user, in, len);
100 }
101
102 static struct lws_protocols protocols[] = {
103 { "raw-test", callback_raw_test, sizeof(struct raw_pss), 0, 0, NULL, 0 },
104 LWS_PROTOCOL_LIST_TERM
105 };
106
107 static int interrupted;
108
sigint_handler(int sig)109 void sigint_handler(int sig)
110 {
111 interrupted = 1;
112 }
113
main(int argc,const char ** argv)114 int main(int argc, const char **argv)
115 {
116 struct lws_context_creation_info info;
117 struct lws_context *context;
118 const char *p;
119 int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
120 /* for LLL_ verbosity above NOTICE to be built into lws,
121 * lws must have been configured and built with
122 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
123 /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
124 /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
125 /* | LLL_DEBUG */;
126
127 signal(SIGINT, sigint_handler);
128
129 if ((p = lws_cmdline_option(argc, argv, "-d")))
130 logs = atoi(p);
131
132 lws_set_log_level(logs, NULL);
133 lwsl_user("LWS minimal raw vhost | nc localhost 7681\n");
134
135 memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
136 info.port = 7681;
137 info.protocols = protocols;
138 info.options = LWS_SERVER_OPTION_ONLY_RAW; /* vhost accepts RAW */
139
140 #if defined(LWS_WITH_TLS)
141 if (lws_cmdline_option(argc, argv, "-s")) {
142 info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
143 info.ssl_cert_filepath = "localhost-100y.cert";
144 info.ssl_private_key_filepath = "localhost-100y.key";
145 }
146 #endif
147
148 context = lws_create_context(&info);
149 if (!context) {
150 lwsl_err("lws init failed\n");
151 return 1;
152 }
153
154 while (n >= 0 && !interrupted)
155 n = lws_service(context, 0);
156
157 lws_context_destroy(context);
158
159 return 0;
160 }
161