deprecate duplicated lws_protocol_get
[platform/upstream/libwebsockets.git] / plugins / protocol_lws_mirror.c
1 /*
2  * libwebsockets-test-server - libwebsockets test implementation
3  *
4  * Copyright (C) 2010-2016 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  * 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
18  * Public Domain.
19  */
20 #include "../lib/libwebsockets.h"
21 #include <string.h>
22 #include <stdlib.h>
23
24 /* lws-mirror_protocol */
25
26 #define MAX_MESSAGE_QUEUE 512
27
28 struct per_session_data__lws_mirror {
29         struct lws *wsi;
30         int ringbuffer_tail;
31 };
32
33 struct a_message {
34         void *payload;
35         size_t len;
36 };
37
38 struct per_vhost_data__lws_mirror {
39         struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
40         int ringbuffer_head;
41 };
42
43 static int
44 callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
45                     void *user, void *in, size_t len)
46 {
47         struct per_session_data__lws_mirror *pss =
48                         (struct per_session_data__lws_mirror *)user;
49         struct per_vhost_data__lws_mirror *v =
50                         (struct per_vhost_data__lws_mirror *)
51                         lws_protocol_vh_priv_get(lws_vhost_get(wsi),
52                                         lws_get_protocol(wsi));
53         int n, m;
54
55         switch (reason) {
56
57         case LWS_CALLBACK_ESTABLISHED:
58                 lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
59                 pss->ringbuffer_tail = v->ringbuffer_head;
60                 pss->wsi = wsi;
61                 break;
62
63         case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
64                 lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi),
65                                 lws_get_protocol(wsi),
66                                 sizeof(struct per_vhost_data__lws_mirror));
67                 break;
68
69         case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
70                 if (!v)
71                         break;
72                 lwsl_info("%s: mirror protocol cleaning up %p\n", __func__, v);
73                 for (n = 0; n < ARRAY_SIZE(v->ringbuffer); n++)
74                         if (v->ringbuffer[n].payload) {
75                                 free(v->ringbuffer[n].payload);
76                                 v->ringbuffer[n].payload = NULL;
77                         }
78                 break;
79
80         case LWS_CALLBACK_SERVER_WRITEABLE:
81                 while (pss->ringbuffer_tail != v->ringbuffer_head) {
82                         m = v->ringbuffer[pss->ringbuffer_tail].len;
83                         n = lws_write(wsi, (unsigned char *)
84                                    v->ringbuffer[pss->ringbuffer_tail].payload +
85                                    LWS_PRE, m, LWS_WRITE_TEXT);
86                         if (n < 0) {
87                                 lwsl_err("ERROR %d writing to mirror socket\n", n);
88                                 return -1;
89                         }
90                         if (n < m)
91                                 lwsl_err("mirror partial write %d vs %d\n", n, m);
92
93                         if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
94                                 pss->ringbuffer_tail = 0;
95                         else
96                                 pss->ringbuffer_tail++;
97
98                         if (((v->ringbuffer_head - pss->ringbuffer_tail) &
99                             (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
100                                 lws_rx_flow_allow_all_protocol(lws_get_context(wsi),
101                                                lws_get_protocol(wsi));
102
103                         if (lws_send_pipe_choked(wsi)) {
104                                 lws_callback_on_writable(wsi);
105                                 break;
106                         }
107                 }
108                 break;
109
110         case LWS_CALLBACK_RECEIVE:
111                 if (((v->ringbuffer_head - pss->ringbuffer_tail) &
112                     (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
113                         lwsl_err("dropping!\n");
114                         goto choke;
115                 }
116
117                 if (v->ringbuffer[v->ringbuffer_head].payload)
118                         free(v->ringbuffer[v->ringbuffer_head].payload);
119
120                 v->ringbuffer[v->ringbuffer_head].payload = malloc(LWS_PRE + len);
121                 v->ringbuffer[v->ringbuffer_head].len = len;
122                 memcpy((char *)v->ringbuffer[v->ringbuffer_head].payload +
123                        LWS_PRE, in, len);
124                 if (v->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
125                         v->ringbuffer_head = 0;
126                 else
127                         v->ringbuffer_head++;
128
129                 if (((v->ringbuffer_head - pss->ringbuffer_tail) &
130                     (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
131                         goto done;
132
133 choke:
134                 lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
135                 lws_rx_flow_control(wsi, 0);
136
137 done:
138                 lws_callback_on_writable_all_protocol(lws_get_context(wsi),
139                                                       lws_get_protocol(wsi));
140                 break;
141
142         default:
143                 break;
144         }
145
146         return 0;
147 }
148
149 static const struct lws_protocols protocols[] = {
150         {
151                 "lws-mirror-protocol",
152                 callback_lws_mirror,
153                 sizeof(struct per_session_data__lws_mirror),
154                 128, /* rx buf size must be >= permessage-deflate rx size */
155         },
156 };
157
158 LWS_VISIBLE int
159 init_protocol_lws_mirror(struct lws_context *context,
160                              struct lws_plugin_capability *c)
161 {
162         if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
163                 lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
164                          c->api_magic);
165                 return 1;
166         }
167
168         c->protocols = protocols;
169         c->count_protocols = ARRAY_SIZE(protocols);
170         c->extensions = NULL;
171         c->count_extensions = 0;
172
173         return 0;
174 }
175
176 LWS_VISIBLE int
177 destroy_protocol_lws_mirror(struct lws_context *context)
178 {
179         return 0;
180 }
181