public api remove context from user callback API BREAK
[platform/upstream/libwebsockets.git] / test-server / test-server-mirror.c
1 /*
2  * libwebsockets-test-server - libwebsockets test implementation
3  *
4  * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21 #include "test-server.h"
22
23 /* lws-mirror_protocol */
24
25 #define MAX_MESSAGE_QUEUE 32
26
27 struct a_message {
28         void *payload;
29         size_t len;
30 };
31
32 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
33 static int ringbuffer_head;
34
35 int
36 callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
37                     void *user, void *in, size_t len)
38 {
39         struct per_session_data__lws_mirror *pss =
40                         (struct per_session_data__lws_mirror *)user;
41         int n;
42
43         switch (reason) {
44
45         case LWS_CALLBACK_ESTABLISHED:
46                 lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
47                 pss->ringbuffer_tail = ringbuffer_head;
48                 pss->wsi = wsi;
49                 break;
50
51         case LWS_CALLBACK_PROTOCOL_DESTROY:
52                 lwsl_notice("%s: mirror protocol cleaning up\n", __func__);
53                 for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++)
54                         if (ringbuffer[n].payload)
55                                 free(ringbuffer[n].payload);
56                 break;
57
58         case LWS_CALLBACK_SERVER_WRITEABLE:
59                 if (close_testing)
60                         break;
61                 while (pss->ringbuffer_tail != ringbuffer_head) {
62
63                         n = lws_write(wsi, (unsigned char *)
64                                    ringbuffer[pss->ringbuffer_tail].payload +
65                                    LWS_SEND_BUFFER_PRE_PADDING,
66                                    ringbuffer[pss->ringbuffer_tail].len,
67                                                                 LWS_WRITE_TEXT);
68                         if (n < 0) {
69                                 lwsl_err("ERROR %d writing to mirror socket\n", n);
70                                 return -1;
71                         }
72                         if (n < (int)ringbuffer[pss->ringbuffer_tail].len)
73                                 lwsl_err("mirror partial write %d vs %d\n",
74                                        n, ringbuffer[pss->ringbuffer_tail].len);
75
76                         if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
77                                 pss->ringbuffer_tail = 0;
78                         else
79                                 pss->ringbuffer_tail++;
80
81                         if (((ringbuffer_head - pss->ringbuffer_tail) &
82                                   (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
83                                 lws_rx_flow_allow_all_protocol(lws_get_ctx(wsi),
84                                                lws_get_protocol(wsi));
85
86                         if (lws_partial_buffered(wsi) || lws_send_pipe_choked(wsi)) {
87                                 lws_callback_on_writable(wsi);
88                                 break;
89                         }
90                 }
91                 break;
92
93         case LWS_CALLBACK_RECEIVE:
94                 if (((ringbuffer_head - pss->ringbuffer_tail) &
95                     (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
96                         lwsl_err("dropping!\n");
97                         goto choke;
98                 }
99
100                 if (ringbuffer[ringbuffer_head].payload)
101                         free(ringbuffer[ringbuffer_head].payload);
102
103                 ringbuffer[ringbuffer_head].payload =
104                                 malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
105                                                   LWS_SEND_BUFFER_POST_PADDING);
106                 ringbuffer[ringbuffer_head].len = len;
107                 memcpy((char *)ringbuffer[ringbuffer_head].payload +
108                                           LWS_SEND_BUFFER_PRE_PADDING, in, len);
109                 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
110                         ringbuffer_head = 0;
111                 else
112                         ringbuffer_head++;
113
114                 if (((ringbuffer_head - pss->ringbuffer_tail) &
115                     (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
116                         goto done;
117
118 choke:
119                 lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
120                 lws_rx_flow_control(wsi, 0);
121
122 done:
123                 lws_callback_on_writable_all_protocol(lws_get_ctx(wsi),
124                                                lws_get_protocol(wsi));
125                 break;
126
127         /*
128          * this just demonstrates how to use the protocol filter. If you won't
129          * study and reject connections based on header content, you don't need
130          * to handle this callback
131          */
132
133         case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
134                 dump_handshake_info(wsi);
135                 /* you could return non-zero here and kill the connection */
136                 break;
137
138         default:
139                 break;
140         }
141
142         return 0;
143 }