test server: only init ssl when --ssl in use
[platform/upstream/libwebsockets.git] / plugins / protocol_lws_raw_test.c
1 /*
2  * ws protocol handler plugin for testing raw file and raw socket
3  *
4  * Copyright (C) 2010-2017 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 plugin test both raw file descriptors and raw socket descriptors.  It
21  * can test both or just one depending on how you configure it.  libwebsockets-
22  * test-server-v2.0 is set up to test both.
23  *
24  * RAW File Descriptor Testing
25  * ===========================
26  *
27  * Enable on a vhost like this
28  *
29  *        "protocol-lws-raw-test": {
30  *                 "status": "ok",
31  *                 "fifo-path": "/tmp/lws-test-raw"
32  *        },
33  *
34  * Then you can feed it data through the FIFO like this
35  *
36  *  $ sudo sh -c "echo hello > /tmp/lws-test-raw"
37  *
38  * This plugin simply prints the data.  But it does it through the lws event
39  * loop / service poll.
40  *
41  *
42  * RAW Socket Descriptor Testing
43  * =============================
44  *
45  * 1) You must give the vhost the option flag LWS_SERVER_OPTION_FALLBACK_TO_RAW
46  *
47  * 2) Enable on a vhost like this
48  *
49  *        "protocol-lws-raw-test": {
50  *                 "status": "ok",
51  *                 "raw": "1"
52  *        },
53  *
54  *    The "raw" pvo marks this protocol as being used for RAW connections.
55  *
56  * 3) Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg
57  *
58  *    telnet 127.0.0.1 7681
59  *
60  *    type something that isn't a valid HTTP method and enter, before the
61  *    connection times out.  The connection will switch to RAW mode using this
62  *    protocol, and pass the unused rx as a raw RX callback.
63  *
64  *    The test protocol echos back what was typed on telnet to telnet.
65  */
66
67 #if !defined (LWS_PLUGIN_STATIC)
68 #define LWS_DLL
69 #define LWS_INTERNAL
70 #include "../lib/libwebsockets.h"
71 #endif
72
73 #include <string.h>
74
75 struct per_vhost_data__raw_test {
76         struct lws_context *context;
77         struct lws_vhost *vhost;
78         const struct lws_protocols *protocol;
79         char fifo_path[100];
80         int fifo;
81         char zero_length_read;
82 };
83
84 struct per_session_data__raw_test {
85         int number;
86         unsigned char buf[128];
87         int len;
88 };
89
90 static int
91 callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
92                         void *user, void *in, size_t len)
93 {
94         struct per_session_data__raw_test *pss =
95                         (struct per_session_data__raw_test *)user;
96         struct per_vhost_data__raw_test *vhd =
97                         (struct per_vhost_data__raw_test *)
98                         lws_protocol_vh_priv_get(lws_get_vhost(wsi),
99                                         lws_get_protocol(wsi));
100         lws_sock_file_fd_type u;
101
102         (void)pss;
103
104         switch (reason) {
105         case LWS_CALLBACK_PROTOCOL_INIT:
106                 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
107                                 lws_get_protocol(wsi),
108                                 sizeof(struct per_vhost_data__raw_test));
109                 vhd->context = lws_get_context(wsi);
110                 vhd->protocol = lws_get_protocol(wsi);
111                 vhd->vhost = lws_get_vhost(wsi);
112                 {
113                         const struct lws_protocol_vhost_options *pvo =
114                                         (const struct lws_protocol_vhost_options *)in;
115                         while (pvo) {
116                                 if (!strcmp(pvo->name, "fifo-path"))
117                                         strncpy(vhd->fifo_path, pvo->value, sizeof(vhd->fifo_path) - 1);
118                                 pvo = pvo->next;
119                         }
120                         if (vhd->fifo_path[0] == '\0') {
121                                 lwsl_err("%s: Missing pvo \"fifo-path\", raw file fd testing disabled\n", __func__);
122                                 break;
123                         }
124                 }
125                 unlink(vhd->fifo_path);
126                 if (mkfifo(vhd->fifo_path, 0666)) {
127                         lwsl_err("mkfifo failed\n");
128                         return 1;
129                 }
130                 vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
131                 if (vhd->fifo == -1) {
132                         lwsl_err("opening fifo failed\n");
133                         unlink(vhd->fifo_path);
134                         return 1;
135                 }
136                 lwsl_notice("FIFO %s created\n", vhd->fifo_path);
137                 u.filefd = vhd->fifo;
138                 if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u,
139                                                 "protocol-lws-raw-test",
140                                                 NULL)) {
141                         lwsl_err("Failed to adopt fifo descriptor\n");
142                         close(vhd->fifo);
143                         unlink(vhd->fifo_path);
144                         return 1;
145                 }
146                 break;
147
148         case LWS_CALLBACK_PROTOCOL_DESTROY:
149                 if (!vhd)
150                         break;
151                 if (vhd->fifo >- 0) {
152                         close(vhd->fifo);
153                         unlink(vhd->fifo_path);
154                 }
155                 break;
156
157
158         /*
159          * Callbacks related to Raw file descriptor testing
160          */
161
162         case LWS_CALLBACK_RAW_ADOPT_FILE:
163                 lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n");
164                 break;
165
166
167         case LWS_CALLBACK_RAW_RX_FILE:
168                 lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n");
169                 {
170                         char buf[256];
171                         int n;
172                         
173                         n = read(vhd->fifo, buf, sizeof(buf) - 1);
174                         if (n < 0) {
175                                 lwsl_err("FIFO read failed\n");
176                                 return 1;
177                         }
178                         /*
179                          * When nobody opened the other side of the FIFO, the FIFO fd acts well and
180                          * only signals POLLIN when somebody opened and wrote to it.
181                          *
182                          * But if the other side of the FIFO closed it, we will see an endless
183                          * POLLIN and 0 available to read.
184                          *
185                          * The only way to handle it is to reopen the FIFO our side and wait for a
186                          * new peer.  This is a quirk of FIFOs not of LWS.
187                          */
188                         if (n == 0) { /* peer closed - do reopen in close processing */
189                                 vhd->zero_length_read = 1;
190                                 return 1;
191                         }
192                         buf[n] = '\0';
193                         lwsl_info("read %d\n", n);
194                         puts(buf);
195                 }
196                 break;
197
198         case LWS_CALLBACK_RAW_CLOSE_FILE:
199                 lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n");
200                 if (vhd->zero_length_read) {
201                         vhd->zero_length_read = 0;
202                         close(vhd->fifo);
203                         /* the wsi that adopted the fifo file is closing... reopen the fifo and readopt */
204                         vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
205                         if (vhd->fifo == -1) {
206                                 lwsl_err("opening fifo failed\n");
207                                 return 1;
208                         }
209                         lwsl_notice("FIFO %s reopened\n", vhd->fifo_path);
210                         u.filefd = vhd->fifo;
211                         if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test", NULL)) {
212                                 lwsl_err("Failed to adopt fifo descriptor\n");
213                                 close(vhd->fifo);
214                                 return 1;
215                         }
216                 }
217                 break;
218
219         case LWS_CALLBACK_RAW_WRITEABLE_FILE:
220                 lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n");
221                 break;
222
223         /*
224          * Callbacks related to Raw socket descriptor testing
225          */
226
227         case LWS_CALLBACK_RAW_ADOPT:
228                 lwsl_notice("LWS_CALLBACK_RAW_ADOPT\n");
229                 break;
230
231         case LWS_CALLBACK_RAW_RX:
232                 lwsl_notice("LWS_CALLBACK_RAW_RX %ld\n", (long)len);
233                 if (len > sizeof(pss->buf))
234                         len = sizeof(pss->buf);
235                 memcpy(pss->buf, in, len);
236                 pss->len = len;
237                 lws_callback_on_writable(wsi);
238                 break;
239
240         case LWS_CALLBACK_RAW_CLOSE:
241                 lwsl_notice("LWS_CALLBACK_RAW_CLOSE\n");
242                 break;
243
244         case LWS_CALLBACK_RAW_WRITEABLE:
245                 lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE\n");
246                 lws_write(wsi, pss->buf, pss->len, LWS_WRITE_HTTP);
247                 break;
248
249         default:
250                 break;
251         }
252
253         return 0;
254 }
255
256 #define LWS_PLUGIN_PROTOCOL_RAW_TEST \
257         { \
258                 "protocol-lws-raw-test", \
259                 callback_raw_test, \
260                 sizeof(struct per_session_data__raw_test), \
261                 1024, /* rx buf size must be >= permessage-deflate rx size */ \
262         }
263
264 #if !defined (LWS_PLUGIN_STATIC)
265                 
266 static const struct lws_protocols protocols[] = {
267         LWS_PLUGIN_PROTOCOL_RAW_TEST
268 };
269
270 LWS_EXTERN LWS_VISIBLE int
271 init_protocol_lws_raw_test(struct lws_context *context,
272                              struct lws_plugin_capability *c)
273 {
274         if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
275                 lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
276                          c->api_magic);
277                 return 1;
278         }
279
280         c->protocols = protocols;
281         c->count_protocols = ARRAY_SIZE(protocols);
282         c->extensions = NULL;
283         c->count_extensions = 0;
284
285         return 0;
286 }
287
288 LWS_EXTERN LWS_VISIBLE int
289 destroy_protocol_lws_raw_test(struct lws_context *context)
290 {
291         return 0;
292 }
293
294 #endif