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