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