multithread stability
[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 512
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, m;
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                         m = ringbuffer[pss->ringbuffer_tail].len;
63                         n = lws_write(wsi, (unsigned char *)
64                                    ringbuffer[pss->ringbuffer_tail].payload +
65                                    LWS_PRE, m, LWS_WRITE_TEXT);
66                         if (n < 0) {
67                                 lwsl_err("ERROR %d writing to mirror socket\n", n);
68                                 return -1;
69                         }
70                         if (n < m)
71                                 lwsl_err("mirror partial write %d vs %d\n", n, m);
72
73                         if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
74                                 pss->ringbuffer_tail = 0;
75                         else
76                                 pss->ringbuffer_tail++;
77
78                         if (((ringbuffer_head - pss->ringbuffer_tail) &
79                             (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
80                                 lws_rx_flow_allow_all_protocol(lws_get_context(wsi),
81                                                lws_get_protocol(wsi));
82
83                         if (lws_send_pipe_choked(wsi)) {
84                                 lws_callback_on_writable(wsi);
85                                 break;
86                         }
87                 }
88                 break;
89
90         case LWS_CALLBACK_RECEIVE:
91                 if (((ringbuffer_head - pss->ringbuffer_tail) &
92                     (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
93                         lwsl_err("dropping!\n");
94                         goto choke;
95                 }
96
97                 if (ringbuffer[ringbuffer_head].payload)
98                         free(ringbuffer[ringbuffer_head].payload);
99
100                 ringbuffer[ringbuffer_head].payload = malloc(LWS_PRE + len);
101                 ringbuffer[ringbuffer_head].len = len;
102                 memcpy((char *)ringbuffer[ringbuffer_head].payload +
103                        LWS_PRE, in, len);
104                 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
105                         ringbuffer_head = 0;
106                 else
107                         ringbuffer_head++;
108
109                 if (((ringbuffer_head - pss->ringbuffer_tail) &
110                     (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
111                         goto done;
112
113 choke:
114                 lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
115                 lws_rx_flow_control(wsi, 0);
116
117 done:
118                 lws_callback_on_writable_all_protocol(lws_get_context(wsi),
119                                                       lws_get_protocol(wsi));
120                 break;
121
122         /*
123          * this just demonstrates how to use the protocol filter. If you won't
124          * study and reject connections based on header content, you don't need
125          * to handle this callback
126          */
127
128         case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
129                 dump_handshake_info(wsi);
130                 /* you could return non-zero here and kill the connection */
131                 break;
132
133         default:
134                 break;
135         }
136
137         return 0;
138 }