libwebsockets-test-server-v2.0 showing how to use mounts and plugins
[platform/upstream/libwebsockets.git] / test-server / fuzxy.c
1 /*
2  * fuzzing proxy - network-level fuzzing injection proxy
3  *
4  * Copyright (C) 2016 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  *
22  * fuzxy is designed to go on the client path
23  *
24  * [ client <-> fuzxy ] <-> server
25  *
26  * you can arrange that with, eg,
27  *
28  *  http_proxy=localhost:8880
29  *
30  * env var before starting the client.
31  *
32  * Even though he is on the client side, he is able to see and change traffic
33  * in both directions, and so fuzz both the client and the server.
34  */
35
36 #if defined(_WIN32) && defined(EXTERNAL_POLL)
37 #define WINVER 0x0600
38 #define _WIN32_WINNT 0x0600
39 #define poll(fdArray, fds, timeout)  WSAPoll((LPWSAPOLLFD)(fdArray), (ULONG)(fds), (INT)(timeout))
40 #endif
41
42 #include "lws_config.h"
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <getopt.h>
47 #include <signal.h>
48 #include <string.h>
49 #include <sys/stat.h>
50 #include <fcntl.h>
51 #include <assert.h>
52 #include <errno.h>
53 #include "../lib/libwebsockets.h"
54
55 #ifdef _WIN32
56 #include <io.h>
57 #include "gettimeofday.h"
58 #else
59 #include <syslog.h>
60 #include <sys/time.h>
61 #include <unistd.h>
62 #include <sys/socket.h>
63 #endif
64
65 #if defined(__NetBSD__)
66 #include <netinet/in.h>
67 #endif
68
69 #define MAX_FUZZ_BUF (1024 * 1024)
70
71 enum types {
72         FZY_S_DEAD              = 0,
73         FZY_S_LISTENING         = 1,
74         FZY_S_ACCEPTED          = 2,
75         FZY_S_PROXIED           = 3,
76         FZY_S_ONWARD            = 4,
77 };
78
79 enum proxy_parser_states {
80         FZY_PP_CONNECT          = 0,
81         FZY_PP_ADDRESS          = 1,
82         FZY_PP_PORT             = 2,
83         FZY_PP_CRLFS            = 3,
84 };
85
86 enum fuzzer_parser_states {
87         FZY_FP_SEARCH           = 0,
88         FZY_FP_SEARCH2          = 1,
89         FZY_FP_INJECT_PREPARE   = 2,
90         FZY_FP_INJECT           = 3,
91         FZY_FP_PENDING          = 4,
92 };
93
94 struct ring {
95         char buf[4096];
96         int head;
97         int tail;
98 };
99
100 struct state {
101         enum types type;
102         enum proxy_parser_states pp;
103         int ppc;
104
105         struct ring in;
106
107         char address[256];
108         int port;
109
110         enum fuzzer_parser_states fp;
111         int fuzc;
112         int pending;
113
114         int twin; /* must be fixed up when arrays lose guys */
115         unsigned int outbound:1; /* from local -> remote */
116         unsigned int is_pending:1;
117
118         unsigned char buf[MAX_FUZZ_BUF];
119         unsigned int inject_len;
120 };
121
122 struct test {
123         const char *s[3];
124         int len[2];
125         unsigned int swallow:1;
126 };
127
128 int force_exit = 0;
129 int which = 5;
130
131 static const struct test tests[] = {
132         { { NULL, "\x0d\x0a\x0d\x0a",
133             "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (248){ 0x89, 0xd2 }, 0x0d, 0x0a },"
134           }, { 0, 4 }, 1 },
135         { { NULL, "\x0d\x0a\x0d\x0a",
136             "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (1373){ 0x89, 0xd2 }, 0x0d, 0x0a },"
137           }, { 0, 4 }, 1 },
138         { { NULL, "\x0d\x0a\x0d\x0a",
139             "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (16967){ 0x89, 0xd2 }, (87){ 0xe2, 0x82, 0xac }, 0x0d, 0x0a },"
140           }, { 0, 4 }, 1 },
141         { { NULL, "\x0d\x0a\x0d\x0a",
142                 "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, "
143                 "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, "
144                 "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, "
145                 "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, "
146                 "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, "
147                 "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, "
148                 "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, "
149                 "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, "
150                 "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, "
151                 "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, "
152                 "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, "
153                 "0xef, 0xbb, 0xbf, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, "
154                 "0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, "
155                 "0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, "
156                 "0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, "
157                 "0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x0d, 0x0a, "
158           }, { 0, 4 }, 1 },
159         { { NULL, "\x0d\x0a\x0d\x0a",
160                 "(20){0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, "
161                 "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, "
162                 "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, "
163                 "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, "
164                 "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, "
165                 "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, "
166                 "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, "
167                 "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, "
168                 "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, "
169                 "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, "
170                 "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, "
171                 "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, "
172                 "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, "
173                 "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, "
174                 "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, "
175                 "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, "
176                 "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, "
177                 "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, "
178                 "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, "
179                 "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, "
180                 "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, "
181                 "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, "
182                 "0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, "
183                 "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, "
184                 "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, "
185                 "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, "
186                 "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, "
187                 "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, "
188                 "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, "
189                 "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, "
190                 "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, "
191                 "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, "
192                 "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, "
193                 "0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, "
194                 "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, "
195                 "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, "
196                 "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, "
197                 "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, "
198                 "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, "
199                 "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, "
200                 "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, "
201                 "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, "
202                 "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, "
203                 "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, "
204                 "0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, "
205                 "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, "
206                 "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, "
207                 "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, "
208                 "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, "
209                 "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, "
210                 "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, "
211                 "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, "
212                 "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, "
213                 "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, "
214                 "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, "
215                 "0x0a, 0xc0, 0x80, 0xef, 0xb7, 0x90, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, "
216                 "0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, "
217                 "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, "
218                 "0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, "
219                 "0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, "
220                 "0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, "
221                 "0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, "
222                 "0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, "
223                 "0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, "
224                 "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, "
225                 "0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, "
226                 "0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, "
227                 "0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, "
228                 "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, "
229                 "0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, "
230                 "0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, "
231                 "0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, "
232                 "0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, "
233                 "0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, "
234                 "0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, "
235                 "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, "
236                 "0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, "
237                 "0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, "
238                 "0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, "
239                 "0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, "
240                 "0x61, 0x64, 0x0d, 0x0a, }"
241         }, { 0, 4 }, 1 },
242         { { NULL, "\x0d\x0a\x0d\x0a",
243                 "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, "
244                 "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, "
245                 "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, "
246                 "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, "
247                 "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, "
248                 "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, "
249                 "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, "
250                 "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, "
251                 "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, "
252                 "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, "
253                 "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, "
254                 "0xef, 0xbb, 0xbf, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, "
255                 "0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, "
256                 "0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, "
257                 "0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, "
258                 "0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x0d, 0x0a, (2048){ 0x0d, 0x0a}"
259           }, { 0, 4 }, 1 },
260 };
261
262 static const int ring_size(struct ring *r)
263 {
264         return sizeof(r->buf);
265 }
266 static const int ring_used(struct ring *r)
267 {
268         return (r->head - r->tail) & (ring_size(r) - 1);
269 }
270 static const int ring_free(struct ring *r)
271 {
272         return (ring_size(r) - 1) - ring_used(r);
273 }
274 static const int ring_get_one(struct ring *r)
275 {
276         int n = r->buf[r->tail] & 255;
277
278         if (r->tail == r->head)
279                 return -1;
280
281         r->tail++;
282         if (r->tail == ring_size(r))
283                 r->tail = 0;
284
285         return n;
286 }
287
288 static int hex(char c)
289 {
290         if (c >= '0' && c <= '9')
291                 return c -'0';
292         if (c >= 'a' && c <= 'f')
293                 return c - 'a' + 10;
294         if (c >='A' && c <= 'F')
295                 return c - 'A' + 10;
296
297         return -1;
298 }
299
300 static int
301 fuzxy_tok(const char **src, unsigned char **buf, int *len)
302 {
303         unsigned char *start;
304         unsigned int count, rlen;
305
306         while (**src) {
307
308                 if (**src == ' ' || **src == ','  || **src == '\n') {
309                         (*src)++;
310                         continue;
311                 }
312
313                 if ((*src)[0] == '}') {
314                         (*src)++;
315                         return 0;
316                 }
317
318                 if ((*src)[0] == '0' && (*src)[1] == 'x') {
319                         if (!len) {
320                                 lwsl_err("out of space\n");
321                                 return -1;
322                         }
323
324                         ((*buf)++)[0] = (hex((*src)[2]) << 4) | hex((*src)[3]);
325                         *src += 4;
326                         (*len)--;
327                 }
328
329                 if (*src[0] == '(') {
330                         start = *buf;
331                         (*src)++;
332                         count = atoi(*src) - 1;
333                         lwsl_err("count %d\n", count);
334                         while (**src && **src != ')')
335                                 (*src)++;
336                         if (!(*src)[0]) {
337                                 lwsl_err("unexpected end in (\n");
338                                 return -1;
339                         }
340                         (*src)++;
341                         while (**src == ' ')
342                                 (*src)++;
343                         if (**src != '{') {
344                                 lwsl_err("missing {\n");
345
346                                 return -1;
347                         }
348                         (*src)++;
349                         if (fuzxy_tok(src, buf, len))
350                                 return -1;
351                         rlen = *buf - start;
352                         while (count--) {
353                                 if (*len < rlen) {
354                                         lwsl_err("out of space\n");
355                                         return -1;
356                                 }
357                                 memcpy(*buf, start, rlen);
358                                 *buf += rlen;
359                                 *len -= rlen;
360                         }
361                 }
362         }
363
364         return 0;
365 }
366
367 static int
368 fuzxy_create_pattern(const char *src, unsigned char *buf, int len)
369 {
370         unsigned char *old = buf;
371         int n;
372
373         while (*src && (*src == '{' || *src == ' '))
374                 src++;
375
376         if (!*src)
377                 return -1;
378
379         n = fuzxy_tok(&src, &buf, &len);
380         if (n)
381                 return -1;
382
383         return buf - old;
384 }
385
386 void sighandler(int sig)
387 {
388         force_exit = 1;
389 }
390
391 static struct option options[] = {
392         { "help",       no_argument,            NULL, 'h' },
393         { "debug",      required_argument,      NULL, 'd' },
394         { "port",       required_argument,      NULL, 'p' },
395         { "ssl",        no_argument,            NULL, 's' },
396         { "allow-non-ssl",      no_argument,    NULL, 'a' },
397         { "interface",  required_argument,      NULL, 'i' },
398         { "closetest",  no_argument,            NULL, 'c' },
399         { "libev",  no_argument,                NULL, 'e' },
400 #ifndef LWS_NO_DAEMONIZE
401         { "daemonize",  no_argument,            NULL, 'D' },
402 #endif
403         { "resource_path", required_argument,   NULL, 'r' },
404         { NULL, 0, 0, 0 }
405 };
406
407 static struct pollfd pfd[128];
408 static struct state state[128];
409 static int pfds = 0;
410
411 static void close_and_remove_fd(int index)
412 {
413         int n;
414
415         lwsl_notice("%s: closing index %d\n", __func__, index);
416         close(pfd[index].fd);
417         pfd[index].fd = -1;
418
419         n = state[index].twin;
420         if (n) {
421                 assert(state[n].twin == index);
422         }
423         state[index].type = FZY_S_DEAD;
424
425         if (index == pfds - 1) {
426                 if (state[index].twin)
427                         state[state[index].twin].twin = 0;
428                 state[index].twin = 0;
429                 goto bail;
430         }
431
432         /* swap the end guy into the deleted guy and trim back one */
433
434         if (state[pfds - 1].twin) {
435                 state[state[pfds - 1].twin].twin = index;
436                 if (n && n == pfds - 1)
437                         n = index;
438         }
439
440         /* swap the last guy into dead guy's place and trim by one */
441         pfd[index] = pfd[pfds - 1];
442         state[index] = state[pfds - 1];
443
444         if (n) {
445                 pfds--;
446                 state[n].twin = 0;
447                 close_and_remove_fd(n);
448                 return;
449         }
450
451 bail:
452         pfds--;
453 }
454
455 static void construct_state(int n, enum types s, int flags)
456 {
457         memset(&state[n], 0, sizeof state[n]);
458         state[n].type = s;
459         pfd[n].events = flags | POLLHUP;
460 }
461
462 static int
463 fuzxy_listen(const char *interface_name, int port, int *sockfd)
464 {
465         struct sockaddr_in serv_addr4;
466         socklen_t len = sizeof(struct sockaddr);
467         struct sockaddr_in sin;
468         int n, opt = 1;
469
470         *sockfd = socket(AF_INET, SOCK_STREAM, 0);
471
472         if (*sockfd == -1) {
473                 lwsl_err("ERROR opening socket\n");
474                 goto bail1;
475         }
476
477         if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR,
478                        (const void *)&opt, sizeof(opt)) < 0) {
479                 lwsl_err("unable to set listen socket options\n");
480                 goto bail2;
481         }
482
483         bzero((char *) &serv_addr4, sizeof(serv_addr4));
484         serv_addr4.sin_addr.s_addr = INADDR_ANY;
485         serv_addr4.sin_family = AF_INET;
486
487         if (interface_name[0] &&
488             lws_interface_to_sa(0, interface_name, (struct sockaddr_in *)
489                                 (struct sockaddr *)&serv_addr4,
490                                 sizeof(serv_addr4)) < 0) {
491                 lwsl_err("Unable to find interface %s\n", interface_name);
492                 goto bail2;
493         }
494
495         serv_addr4.sin_port = htons(port);
496
497         n = bind(*sockfd, (struct sockaddr *)&serv_addr4,
498                                 sizeof(serv_addr4));
499         if (n < 0) {
500                 lwsl_err("ERROR on binding to port %d (%d %d)\n",
501                          port, n, errno);
502                 goto bail2;
503         }
504
505         if (getsockname(*sockfd, (struct sockaddr *)&sin, &len) == -1)
506                 lwsl_warn("getsockname: %s\n", strerror(errno));
507         else
508                 port = ntohs(sin.sin_port);
509
510         listen(*sockfd, SOMAXCONN);
511
512         return 0;
513 bail2:
514         close(*sockfd);
515 bail1:
516         return -1;
517 }
518
519
520 static int fuzz(int n, char *out, int len)
521 {
522         struct state *s = &state[n];
523         const struct test *t = &tests[which];
524         int m = 0;
525         int c;
526
527         while (m < len) {
528                 switch (s->fp) {
529                 case FZY_FP_SEARCH:
530                         if (t->s[0] == NULL) {
531                                 s->fuzc = 0;
532                                 s->is_pending = 0;
533                                 s->fp = FZY_FP_SEARCH2;
534                                 goto search2;
535                         }
536                         c = ring_get_one(&state[s->twin].in);
537                         if (c < 0)
538                                 return m;
539                         if (c == tests[which].s[0][s->fuzc++]) {
540                                 if (s->fuzc == t->len[0]) {
541                                         s->fuzc = 0;
542                                         s->fp = FZY_FP_SEARCH2;
543                                 }
544                         } else
545                                 s->fuzc = 0;
546                         out[m++] = c;
547                         break;
548
549                 case FZY_FP_SEARCH2:
550 search2:
551                         if (tests[which].s[1] == NULL) {
552                                 s->fuzc = 0;
553                                 s->is_pending = 0;
554                                 s->fp = FZY_FP_INJECT_PREPARE;
555                                 goto inject;
556                         }
557                         c = ring_get_one(&state[s->twin].in);
558                         if (c < 0)
559                                 return m;
560                         if (c == tests[which].s[1][s->fuzc++]) {
561                                 if (s->fuzc == tests[which].len[1]) {
562                                         lwsl_notice("+++++++fuzzer hit...\n");
563                                         s->fuzc = 0;
564                                         s->fp = FZY_FP_INJECT_PREPARE;
565                                         s->is_pending = !t->swallow;
566                                         s->pending = c;
567                                         goto inject;
568                                 }
569                         } else
570                                 s->fuzc = 0;
571                         if (!t->swallow)
572                                 out[m++] = c;
573                         break;
574
575                 case FZY_FP_INJECT_PREPARE:
576 inject:
577                         s->inject_len = fuzxy_create_pattern(t->s[2],
578                                 s->buf, sizeof(s->buf));
579                         if (s->inject_len == (unsigned int) -1)
580                                 return -1;
581                         s->fp = FZY_FP_INJECT;
582                         /* fallthru */
583
584                 case FZY_FP_INJECT:
585                         out[m++] = s->buf[s->fuzc++];
586                         if (s->fuzc == s->inject_len)
587                                 s->fp = FZY_FP_PENDING;
588                         break;
589
590                 case FZY_FP_PENDING:
591                         if (s->is_pending)
592                                 out[m++] = s->pending;
593                         s->fp = FZY_FP_SEARCH;
594                         s->fuzc = 0;
595                         break;
596                 }
597         }
598
599         return m;
600 }
601
602 static int
603 handle_accept(int n)
604 {
605         struct addrinfo ai, *res, *result;
606         struct sockaddr_in serv_addr4;
607         struct state *s = &state[n];
608         void *p = NULL;
609         int m, sockfd;
610
611         while (1) {
612                 m = ring_get_one(&s->in);
613                 if (m < 0)
614                         return 0;
615
616                 switch (s->pp) {
617                 case FZY_PP_CONNECT:
618                         if (m != "CONNECT "[s->ppc++]) {
619                                 lwsl_notice("failed CONNECT match\n");
620                                 return 1;
621                         }
622                         if (s->ppc == 8) {
623                                 s->pp = FZY_PP_ADDRESS;
624                                 s->ppc = 0;
625                         }
626                         break;
627                 case FZY_PP_ADDRESS:
628                         if (m == ':') {
629                                 s->address[s->ppc++] = '\0';
630                                 s->pp = FZY_PP_PORT;
631                                 s->ppc = 0;
632                                 break;
633                         }
634                         if (m == ' ') {
635                                 s->address[s->ppc++] = '\0';
636                                 s->pp = FZY_PP_CRLFS;
637                                 s->ppc = 0;
638                                 break;
639                         }
640
641
642                         s->address[s->ppc++] = m;
643                         if (s->ppc == sizeof(s->address)) {
644                                 lwsl_notice("Failed on address length\n");
645                                 return 1;
646                         }
647                         break;
648                 case FZY_PP_PORT:
649                         if (m == ' ') {
650                                 s->pp = FZY_PP_CRLFS;
651                                 s->ppc = 0;
652                                 break;
653                         }
654                         if (m >= '0' && m <= '9') {
655                                 s->port *= 10;
656                                 s->port += m - '0';
657                                 break;
658                         }
659                         return 1;
660
661                 case FZY_PP_CRLFS:
662                         if (m != "\x0d\x0a\x0d\x0a"[s->ppc++])
663                                 s->ppc = 0;
664                         if (s->ppc != 4)
665                                 break;
666                         s->type = FZY_S_PROXIED;
667
668                         memset (&ai, 0, sizeof ai);
669                         ai.ai_family = PF_UNSPEC;
670                         ai.ai_socktype = SOCK_STREAM;
671                         ai.ai_flags = AI_CANONNAME;
672
673                         if (getaddrinfo(s->address, NULL, &ai, &result)) {
674                                 lwsl_notice("failed to lookup %s\n",
675                                             s->address);
676                                 return 1;
677                         }
678
679                         res = result;
680                         while (!p && res) {
681                                 switch (res->ai_family) {
682                                 case AF_INET:
683                                         p = &((struct sockaddr_in *)res->
684                                               ai_addr)->sin_addr;
685                                         break;
686                                 }
687
688                                 res = res->ai_next;
689                         }
690
691                         if (!p) {
692                                 lwsl_notice("Failed to get address result %s\n",
693                                             s->address);
694                                 freeaddrinfo(result);
695                                 return 1;
696                         }
697
698                         serv_addr4.sin_family = AF_INET;
699                         serv_addr4.sin_addr = *((struct in_addr *)p);
700                         serv_addr4.sin_port = htons(s->port);
701                         bzero(&serv_addr4.sin_zero, 8);
702                         freeaddrinfo(result);
703
704                         lwsl_err("Conn %d req '%s' port %d\n", n,
705                                  s->address, s->port);
706                         /* we need to open the associated onward connection */
707                         sockfd = socket(AF_INET, SOCK_STREAM, 0);
708                         if (sockfd < 0) {
709                                 lwsl_err("Could not get socket\n");
710                                 return -1;
711                         }
712
713                         if (connect(sockfd, (struct sockaddr *)&serv_addr4,
714                                     sizeof(struct sockaddr)) == -1 ||
715                             errno == EISCONN) {
716                                 close(sockfd);
717                                 lwsl_err("proxied onward connection failed\n");
718                                 return 1;
719                         }
720                         s->twin = pfds;
721                         construct_state(pfds, FZY_S_ONWARD,
722                                         POLLOUT | POLLIN | POLLERR);
723                         state[pfds].twin = n;
724                         lwsl_notice("binding conns %d and %d\n", n, pfds);
725                         state[pfds].outbound = s->outbound;
726                         state[pfds].ppc = 0;
727                         pfd[pfds++].fd = sockfd;
728
729                         lwsl_notice("onward connection in progress\n");
730                         if (ring_used(&s->in))
731                                 pfd[s->twin].events |= POLLOUT;
732                         if (write(pfd[n].fd,
733                                   "HTTP/1.0 200 \x0d\x0a\x0d\x0a", 17) < 17)
734                                 return 1;
735                 }
736         }
737
738         return 0;
739 }
740
741 static void sigpipe_handler(int x)
742 {
743 }
744
745 int
746 main(int argc, char **argv)
747 {
748         char interface_name[128] = "", interface_name_local[128] = "lo";
749         int port_local = 8880, accept_fd;
750         struct sockaddr_in cli_addr;
751         int debug_level = 7;
752         socklen_t clilen;
753         struct state *s;
754         char out[4096];
755         int opts = 0;
756         int n = 0, m;
757
758 #ifndef _WIN32
759         int syslog_options = LOG_PID | LOG_PERROR;
760 #endif
761 #ifndef LWS_NO_DAEMONIZE
762         int daemonize = 0;
763 #endif
764         signal(SIGPIPE, sigpipe_handler);
765
766         while (n >= 0) {
767                 n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
768                 if (n < 0)
769                         continue;
770                 switch (n) {
771                 case 'e':
772                         opts |= LWS_SERVER_OPTION_LIBEV;
773                         break;
774 #ifndef LWS_NO_DAEMONIZE
775                 case 'D':
776                         daemonize = 1;
777                         #ifndef _WIN32
778                         syslog_options &= ~LOG_PERROR;
779                         #endif
780                         break;
781 #endif
782                 case 'd':
783                         debug_level = atoi(optarg);
784                         break;
785                 case 'p':
786                         port_local = atoi(optarg);
787                         break;
788                 case 'i':
789                         strncpy(interface_name, optarg, sizeof interface_name);
790                         interface_name[(sizeof interface_name) - 1] = '\0';
791                         break;
792                 case 'h':
793                         fprintf(stderr, "Usage: libwebsockets-test-fuzxy "
794                                         "[--port=<p>] [--ssl] "
795                                         "[-d <log bitfield>] "
796                                         "[--resource_path <path>]\n");
797                         exit(1);
798                 }
799         }
800
801 #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
802         /*
803          * normally lock path would be /var/lock/lwsts or similar, to
804          * simplify getting started without having to take care about
805          * permissions or running as root, set to /tmp/.lwsts-lock
806          */
807         if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
808                 fprintf(stderr, "Failed to daemonize\n");
809                 return 1;
810         }
811 #endif
812
813         signal(SIGINT, sighandler);
814
815 #ifndef _WIN32
816         /* we will only try to log things according to our debug_level */
817         setlogmask(LOG_UPTO (LOG_DEBUG));
818         openlog("fuzxy", syslog_options, LOG_DAEMON);
819 #endif
820
821         /* tell the library what debug level to emit and to send it to syslog */
822         lws_set_log_level(debug_level, lwsl_emit_syslog);
823
824         lwsl_notice("libwebsockets fuzzing proxy - license LGPL2.1+SLE\n");
825         lwsl_notice("(C) Copyright 2016 Andy Green <andy@warmcat.com>\n");
826
827         /* listen on local side */
828
829         if (fuzxy_listen(interface_name, port_local, &pfd[pfds].fd)) {
830                 lwsl_err("Failed to listen on local side\n");
831                 goto bail1;
832         }
833         construct_state(pfds, FZY_S_LISTENING, POLLIN | POLLERR);
834         pfds++;
835
836         lwsl_notice("Local side listening on %s:%u\n",
837                     interface_name_local, port_local);
838
839         while (!force_exit) {
840
841                 m = poll(pfd, pfds, 50);
842                 if (m < 0)
843                         continue;
844                 for (n = 0; n < pfds; n++) {
845                         s = &state[n];
846                         if (s->type == FZY_S_LISTENING &&
847                             (pfd[n].revents & POLLIN)) {
848                                 /* first do the accept entry */
849
850                                 clilen = sizeof(cli_addr);
851                                 accept_fd = accept(pfd[0].fd,
852                                          (struct sockaddr *)&cli_addr, &clilen);
853                                 if (accept_fd < 0) {
854                                         if (errno == EAGAIN ||
855                                             errno == EWOULDBLOCK)
856                                                 continue;
857
858                                         lwsl_warn("ERROR on accept: %s\n",
859                                                   strerror(errno));
860                                         continue;
861                                 }
862                                 construct_state(pfds, FZY_S_ACCEPTED,
863                                                 POLLIN | POLLERR);
864                                 state[pfds].outbound = n == 0;
865                                 state[pfds].pp = FZY_PP_CONNECT;
866                                 state[pfds].ppc = 0;
867                                 pfd[pfds++].fd = accept_fd;
868                                 lwsl_notice("new connect accepted\n");
869                                 continue;
870                         }
871                         if (pfd[n].revents & POLLIN) {
872                                 assert(ring_free(&s->in));
873                                 m = (ring_size(&s->in) - 1) -
874                                     s->in.head;
875                                 if (s->in.head == ring_size(&s->in) - 1 &&
876                                     s->in.tail)
877                                         m = 1;
878                                 m = read(pfd[n].fd, s->in.buf + s->in.head, m);
879 //                              lwsl_notice("read %d\n", m);
880                                 if (m <= 0) {
881                                         lwsl_err("Error on read\n");
882                                         goto drop;
883                                 }
884                                 s->in.head += m;
885                                 if (s->in.head == ring_size(&s->in))
886                                         s->in.head = 0;
887
888                                 switch (s->type) {
889                                 case FZY_S_ACCEPTED: /* parse proxy CONNECT */
890                                         if (handle_accept(n))
891                                                 goto drop;
892                                         break;
893                                 case FZY_S_PROXIED:
894                                 case FZY_S_ONWARD:
895                                         if (ring_used(&s->in))
896                                                 pfd[s->twin].events |= POLLOUT;
897                                         break;
898                                 default:
899                                         assert(0);
900                                         break;
901                                 }
902                                 if (s->in.head == s->in.tail) {
903                                         s->in.head = s->in.tail = 0;
904                                         pfd[n].events |= POLLIN;
905                                 }
906                                 if (!ring_free(&s->in))
907                                         pfd[n].events &= ~POLLIN;
908                         }
909                         if (pfd[n].revents & POLLOUT) {
910                                 switch (s->type) {
911                                 case FZY_S_PROXIED:
912                                 case FZY_S_ONWARD:
913                                         /*
914                                          * draw down enough of the partner's
915                                          * in ring to either exhaust it
916                                          * or fill an output buffer
917                                          */
918                                         m = fuzz(n, out, sizeof(out));
919                                         if (m < 0) {
920                                                 lwsl_err("Error on fuzz\n");
921                                                 goto drop;
922                                         }
923                                         lwsl_notice("got block %d\n", m);
924                                         if (m) {
925                                                 m = write(pfd[n].fd, out, m);
926                                                 if (m <= 0) {
927                                                         lwsl_err("Error on write\n");
928                                                         goto drop;
929                                                 } else
930                                                         pfd[s->twin].events &= ~POLLIN;
931                                         } else {
932                                                 pfd[n].events &= ~POLLOUT;
933
934                                                 if (ring_free(&state[s->twin].in))
935                                                         pfd[s->twin].events |= POLLIN;
936                                         }
937
938                                         break;
939                                 default:
940                                         break;
941                                 }
942                         }
943
944                         continue;
945 drop:
946                         close_and_remove_fd(n);
947                         n--; /* redo this slot */
948                 }
949         }
950
951 bail1:
952         lwsl_notice("%s exited cleanly\n", argv[0]);
953
954 #ifndef _WIN32
955         closelog();
956 #endif
957
958         return 0;
959 }