mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
fuzxy
This is the initial push of a fuzzing proxy we will use for testing lws. Run libwebsockets-test-fuzxy and the test server if it's local. Then run the test client with http_proxy=localhost:8880 libwebsockets-test-client localhost (or whatever) Right now he only fuzzes one thing but he is operational as a proxy.
This commit is contained in:
parent
a547554aa2
commit
4319b4d78d
2 changed files with 690 additions and 0 deletions
|
@ -786,6 +786,13 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
"test-server/test-server-dumb-increment.c"
|
||||
"test-server/test-server-mirror.c"
|
||||
"test-server/test-server-echogen.c")
|
||||
if (UNIX)
|
||||
create_test_app(test-fuzxy "test-server/fuzxy.c"
|
||||
""
|
||||
""
|
||||
""
|
||||
"")
|
||||
endif()
|
||||
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")))
|
||||
create_test_app(test-server-pthreads
|
||||
"test-server/test-server-pthreads.c"
|
||||
|
|
683
test-server/fuzxy.c
Normal file
683
test-server/fuzxy.c
Normal file
|
@ -0,0 +1,683 @@
|
|||
/*
|
||||
* fuzzing proxy - network-level fuzzing injection proxy
|
||||
*
|
||||
* Copyright (C) 2016 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
*
|
||||
* fuzxy is designed to go on the client path
|
||||
*
|
||||
* [ client <-> fuzxy ] <-> server
|
||||
*
|
||||
* you can arrange that with, eg,
|
||||
*
|
||||
* http_proxy=localhost:8880
|
||||
*
|
||||
* env var before starting the client.
|
||||
*
|
||||
* Even though he is on the client side, he is able to see and change traffic
|
||||
* in both directions, and so fuzz both the client and the server.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && defined(EXTERNAL_POLL)
|
||||
#define WINVER 0x0600
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#define poll(fdArray, fds, timeout) WSAPoll((LPWSAPOLLFD)(fdArray), (ULONG)(fds), (INT)(timeout))
|
||||
#endif
|
||||
|
||||
#include "lws_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include "../lib/libwebsockets.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include "gettimeofday.h"
|
||||
#else
|
||||
#include <syslog.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
enum types {
|
||||
FZY_S_DEAD = 0,
|
||||
FZY_S_LISTENING = 1,
|
||||
FZY_S_ACCEPTED = 2,
|
||||
FZY_S_PROXIED = 3,
|
||||
FZY_S_ONWARD = 4,
|
||||
};
|
||||
|
||||
enum proxy_parser_states {
|
||||
FZY_PP_CONNECT = 0,
|
||||
FZY_PP_ADDRESS = 1,
|
||||
FZY_PP_PORT = 2,
|
||||
FZY_PP_CRLFS = 3,
|
||||
};
|
||||
|
||||
enum fuzzer_parser_states {
|
||||
FZY_FP_SEARCH = 0,
|
||||
FZY_FP_SEARCH2 = 1,
|
||||
FZY_FP_INJECT = 2,
|
||||
FZY_FP_PENDING = 3,
|
||||
};
|
||||
|
||||
struct ring {
|
||||
char buf[4096];
|
||||
int head;
|
||||
int tail;
|
||||
};
|
||||
|
||||
struct state {
|
||||
enum types type;
|
||||
enum proxy_parser_states pp;
|
||||
int ppc;
|
||||
|
||||
struct ring in;
|
||||
|
||||
char address[256];
|
||||
int port;
|
||||
|
||||
enum fuzzer_parser_states fp;
|
||||
int fuzc;
|
||||
int pending;
|
||||
|
||||
int twin; /* must be fixed up when arrays lose guys */
|
||||
unsigned int outbound:1; /* from local -> remote */
|
||||
};
|
||||
|
||||
|
||||
int force_exit = 0;
|
||||
|
||||
static const int ring_size(struct ring *r)
|
||||
{
|
||||
return sizeof(r->buf);
|
||||
}
|
||||
static const int ring_used(struct ring *r)
|
||||
{
|
||||
return (r->head - r->tail) & (ring_size(r) - 1);
|
||||
}
|
||||
static const int ring_free(struct ring *r)
|
||||
{
|
||||
return (ring_size(r) - 1) - ring_used(r);
|
||||
}
|
||||
static const int ring_get_one(struct ring *r)
|
||||
{
|
||||
int n = r->buf[r->tail] & 255;
|
||||
|
||||
if (r->tail == r->head)
|
||||
return -1;
|
||||
|
||||
r->tail++;
|
||||
if (r->tail == ring_size(r))
|
||||
r->tail = 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void sighandler(int sig)
|
||||
{
|
||||
force_exit = 1;
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "debug", required_argument, NULL, 'd' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "ssl", no_argument, NULL, 's' },
|
||||
{ "allow-non-ssl", no_argument, NULL, 'a' },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
{ "closetest", no_argument, NULL, 'c' },
|
||||
{ "libev", no_argument, NULL, 'e' },
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
{ "daemonize", no_argument, NULL, 'D' },
|
||||
#endif
|
||||
{ "resource_path", required_argument, NULL, 'r' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static struct pollfd pfd[128];
|
||||
static struct state state[128];
|
||||
static int pfds = 0;
|
||||
|
||||
static void close_and_remove_fd(int index)
|
||||
{
|
||||
int n;
|
||||
|
||||
lwsl_notice("%s: closing index %d\n", __func__, index);
|
||||
close(pfd[index].fd);
|
||||
pfd[index].fd = -1;
|
||||
|
||||
n = state[index].twin;
|
||||
if (n) {
|
||||
assert(state[n].twin == index);
|
||||
}
|
||||
state[index].type = FZY_S_DEAD;
|
||||
|
||||
if (index == pfds - 1) {
|
||||
if (state[index].twin)
|
||||
state[state[index].twin].twin = 0;
|
||||
state[index].twin = 0;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* swap the end guy into the deleted guy and trim back one */
|
||||
|
||||
if (state[pfds - 1].twin) {
|
||||
state[state[pfds - 1].twin].twin = index;
|
||||
if (n && n == pfds - 1)
|
||||
n = index;
|
||||
}
|
||||
|
||||
/* swap the last guy into dead guy's place and trim by one */
|
||||
pfd[index] = pfd[pfds - 1];
|
||||
state[index] = state[pfds - 1];
|
||||
|
||||
if (n) {
|
||||
pfds--;
|
||||
state[n].twin = 0;
|
||||
close_and_remove_fd(n);
|
||||
return;
|
||||
}
|
||||
|
||||
bail:
|
||||
pfds--;
|
||||
}
|
||||
|
||||
static void construct_state(int n, enum types s, int flags)
|
||||
{
|
||||
memset(&state[n], 0, sizeof state[n]);
|
||||
state[n].type = s;
|
||||
pfd[n].events = flags | POLLHUP;
|
||||
}
|
||||
|
||||
static int
|
||||
fuzxy_listen(const char *interface_name, int port, int *sockfd)
|
||||
{
|
||||
struct sockaddr_in serv_addr4;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
struct sockaddr_in sin;
|
||||
int n, opt = 1;
|
||||
|
||||
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (*sockfd == -1) {
|
||||
lwsl_err("ERROR opening socket\n");
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const void *)&opt, sizeof(opt)) < 0) {
|
||||
lwsl_err("unable to set listen socket options\n");
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
bzero((char *) &serv_addr4, sizeof(serv_addr4));
|
||||
serv_addr4.sin_addr.s_addr = INADDR_ANY;
|
||||
serv_addr4.sin_family = AF_INET;
|
||||
|
||||
if (interface_name[0] &&
|
||||
lws_interface_to_sa(0, interface_name, (struct sockaddr_in *)
|
||||
(struct sockaddr *)&serv_addr4,
|
||||
sizeof(serv_addr4)) < 0) {
|
||||
lwsl_err("Unable to find interface %s\n", interface_name);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
serv_addr4.sin_port = htons(port);
|
||||
|
||||
n = bind(*sockfd, (struct sockaddr *)&serv_addr4,
|
||||
sizeof(serv_addr4));
|
||||
if (n < 0) {
|
||||
lwsl_err("ERROR on binding to port %d (%d %d)\n",
|
||||
port, n, errno);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
if (getsockname(*sockfd, (struct sockaddr *)&sin, &len) == -1)
|
||||
lwsl_warn("getsockname: %s\n", strerror(errno));
|
||||
else
|
||||
port = ntohs(sin.sin_port);
|
||||
|
||||
listen(*sockfd, SOMAXCONN);
|
||||
|
||||
return 0;
|
||||
bail2:
|
||||
close(*sockfd);
|
||||
bail1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct fuzxy_rule {
|
||||
const char *s[3];
|
||||
int len[3];
|
||||
int inject_len;
|
||||
};
|
||||
|
||||
struct fuzxy_rule r = {
|
||||
{ "Host:", "\x0d", " \x0d" },
|
||||
{ 5, 1, 2 },
|
||||
65536
|
||||
};
|
||||
|
||||
static int fuzz(int n, char *out, int len)
|
||||
{
|
||||
struct state *s = &state[n];
|
||||
int m = 0;
|
||||
int c;
|
||||
|
||||
while (m < len) {
|
||||
switch (s->fp) {
|
||||
case FZY_FP_SEARCH:
|
||||
c = ring_get_one(&state[s->twin].in);
|
||||
if (c < 0)
|
||||
return m;
|
||||
if (c == r.s[0][s->fuzc++]) {
|
||||
if (s->fuzc == r.len[0]) {
|
||||
s->fuzc = 0;
|
||||
s->fp = FZY_FP_SEARCH2;
|
||||
}
|
||||
} else
|
||||
s->fuzc = 0;
|
||||
out[m++] = c;
|
||||
break;
|
||||
|
||||
case FZY_FP_SEARCH2:
|
||||
c = ring_get_one(&state[s->twin].in);
|
||||
if (c < 0)
|
||||
return m;
|
||||
if (c == r.s[1][s->fuzc++]) {
|
||||
if (s->fuzc == r.len[1]) {
|
||||
lwsl_notice("+++++++fuzzer hit...\n");
|
||||
s->fuzc = 0;
|
||||
s->fp = FZY_FP_INJECT;
|
||||
s->pending = c;
|
||||
goto inject;
|
||||
}
|
||||
} else
|
||||
s->fuzc = 0;
|
||||
out[m++] = c;
|
||||
break;
|
||||
case FZY_FP_INJECT:
|
||||
inject:
|
||||
out[m++] = r.s[2][s->fuzc++ % r.len[2]];
|
||||
if (s->fuzc == r.inject_len)
|
||||
s->fp = FZY_FP_PENDING;
|
||||
break;
|
||||
|
||||
case FZY_FP_PENDING:
|
||||
out[m++] = s->pending;
|
||||
s->fp = FZY_FP_SEARCH;
|
||||
s->fuzc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_accept(int n)
|
||||
{
|
||||
struct addrinfo ai, *res, *result;
|
||||
struct sockaddr_in serv_addr4;
|
||||
struct state *s = &state[n];
|
||||
void *p = NULL;
|
||||
int m, sockfd;
|
||||
|
||||
while (1) {
|
||||
m = ring_get_one(&s->in);
|
||||
if (m < 0)
|
||||
return 0;
|
||||
|
||||
switch (s->pp) {
|
||||
case FZY_PP_CONNECT:
|
||||
if (m != "CONNECT "[s->ppc++]) {
|
||||
lwsl_notice("failed CONNECT match\n");
|
||||
return 1;
|
||||
}
|
||||
if (s->ppc == 8) {
|
||||
s->pp = FZY_PP_ADDRESS;
|
||||
s->ppc = 0;
|
||||
}
|
||||
break;
|
||||
case FZY_PP_ADDRESS:
|
||||
if (m == ':') {
|
||||
s->address[s->ppc++] = '\0';
|
||||
s->pp = FZY_PP_PORT;
|
||||
s->ppc = 0;
|
||||
break;
|
||||
}
|
||||
if (m == ' ') {
|
||||
s->address[s->ppc++] = '\0';
|
||||
s->pp = FZY_PP_CRLFS;
|
||||
s->ppc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
s->address[s->ppc++] = m;
|
||||
if (s->ppc == sizeof(s->address)) {
|
||||
lwsl_notice("Failed on address length\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case FZY_PP_PORT:
|
||||
if (m == ' ') {
|
||||
s->pp = FZY_PP_CRLFS;
|
||||
s->ppc = 0;
|
||||
break;
|
||||
}
|
||||
if (m >= '0' && m <= '9') {
|
||||
s->port *= 10;
|
||||
s->port += m - '0';
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case FZY_PP_CRLFS:
|
||||
if (m != "\x0d\x0a\x0d\x0a"[s->ppc++])
|
||||
s->ppc = 0;
|
||||
if (s->ppc != 4)
|
||||
break;
|
||||
s->type = FZY_S_PROXIED;
|
||||
|
||||
memset (&ai, 0, sizeof ai);
|
||||
ai.ai_family = PF_UNSPEC;
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
ai.ai_flags = AI_CANONNAME;
|
||||
|
||||
if (getaddrinfo(s->address, NULL, &ai, &result)) {
|
||||
lwsl_notice("failed to lookup %s\n",
|
||||
s->address);
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = result;
|
||||
while (!p && res) {
|
||||
switch (res->ai_family) {
|
||||
case AF_INET:
|
||||
p = &((struct sockaddr_in *)res->
|
||||
ai_addr)->sin_addr;
|
||||
break;
|
||||
}
|
||||
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
lwsl_notice("Failed to get address result %s\n",
|
||||
s->address);
|
||||
freeaddrinfo(result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
serv_addr4.sin_family = AF_INET;
|
||||
serv_addr4.sin_addr = *((struct in_addr *)p);
|
||||
serv_addr4.sin_port = htons(s->port);
|
||||
bzero(&serv_addr4.sin_zero, 8);
|
||||
freeaddrinfo(result);
|
||||
|
||||
lwsl_err("Conn %d req '%s' port %d\n", n,
|
||||
s->address, s->port);
|
||||
/* we need to open the associated onward connection */
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&serv_addr4,
|
||||
sizeof(struct sockaddr)) == -1 ||
|
||||
errno == EISCONN) {
|
||||
lwsl_err("proxied onward connection failed\n");
|
||||
return 1;
|
||||
}
|
||||
s->twin = pfds;
|
||||
construct_state(pfds, FZY_S_ONWARD,
|
||||
POLLOUT | POLLIN | POLLERR);
|
||||
state[pfds].twin = n;
|
||||
lwsl_notice("binding conns %d and %d\n", n, pfds);
|
||||
state[pfds].outbound = s->outbound;
|
||||
state[pfds].ppc = 0;
|
||||
pfd[pfds++].fd = sockfd;
|
||||
|
||||
lwsl_notice("onward connection in progress\n");
|
||||
if (ring_used(&s->in))
|
||||
pfd[s->twin].events |= POLLOUT;
|
||||
if (write(pfd[n].fd,
|
||||
"HTTP/1.0 200 \x0d\x0a\x0d\x0a", 17) < 17)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sigpipe_handler(int x)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char interface_name[128] = "", interface_name_local[128] = "lo";
|
||||
int port_local = 8880, accept_fd;
|
||||
struct sockaddr_in cli_addr;
|
||||
int debug_level = 7;
|
||||
socklen_t clilen;
|
||||
struct state *s;
|
||||
char out[4096];
|
||||
int opts = 0;
|
||||
int n = 0, m;
|
||||
|
||||
#ifndef _WIN32
|
||||
int syslog_options = LOG_PID | LOG_PERROR;
|
||||
#endif
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
int daemonize = 0;
|
||||
#endif
|
||||
signal(SIGPIPE, sigpipe_handler);
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
case 'e':
|
||||
opts |= LWS_SERVER_OPTION_LIBEV;
|
||||
break;
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
case 'D':
|
||||
daemonize = 1;
|
||||
#ifndef _WIN32
|
||||
syslog_options &= ~LOG_PERROR;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
case 'd':
|
||||
debug_level = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
port_local = atoi(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(interface_name, optarg, sizeof interface_name);
|
||||
interface_name[(sizeof interface_name) - 1] = '\0';
|
||||
break;
|
||||
case 'h':
|
||||
fprintf(stderr, "Usage: libwebsockets-test-fuzxy "
|
||||
"[--port=<p>] [--ssl] "
|
||||
"[-d <log bitfield>] "
|
||||
"[--resource_path <path>]\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
|
||||
/*
|
||||
* normally lock path would be /var/lock/lwsts or similar, to
|
||||
* simplify getting started without having to take care about
|
||||
* permissions or running as root, set to /tmp/.lwsts-lock
|
||||
*/
|
||||
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
|
||||
fprintf(stderr, "Failed to daemonize\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
signal(SIGINT, sighandler);
|
||||
|
||||
#ifndef _WIN32
|
||||
/* we will only try to log things according to our debug_level */
|
||||
setlogmask(LOG_UPTO (LOG_DEBUG));
|
||||
openlog("fuzxy", syslog_options, LOG_DAEMON);
|
||||
#endif
|
||||
|
||||
/* tell the library what debug level to emit and to send it to syslog */
|
||||
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
||||
|
||||
lwsl_notice("%s\n(C) Copyright 2016 Andy Green <andy@warmcat.com> - "
|
||||
"licensed under LGPL2.1\n", argv[0]);
|
||||
|
||||
/* listen on local side */
|
||||
|
||||
if (fuzxy_listen(interface_name, port_local, &pfd[pfds].fd)) {
|
||||
lwsl_err("Failed to listen on local side\n");
|
||||
goto bail1;
|
||||
}
|
||||
construct_state(pfds, FZY_S_LISTENING, POLLIN | POLLERR);
|
||||
pfds++;
|
||||
|
||||
lwsl_notice("Local side listening on %s:%u\n",
|
||||
interface_name_local, port_local);
|
||||
|
||||
while (!force_exit) {
|
||||
|
||||
m = poll(pfd, pfds, 50);
|
||||
if (m < 0)
|
||||
continue;
|
||||
for (n = 0; n < pfds; n++) {
|
||||
s = &state[n];
|
||||
if (s->type == FZY_S_LISTENING &&
|
||||
(pfd[n].revents & POLLIN)) {
|
||||
/* first do the accept entry */
|
||||
|
||||
clilen = sizeof(cli_addr);
|
||||
accept_fd = accept(pfd[0].fd,
|
||||
(struct sockaddr *)&cli_addr, &clilen);
|
||||
if (accept_fd < 0) {
|
||||
if (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK)
|
||||
continue;
|
||||
|
||||
lwsl_warn("ERROR on accept: %s\n",
|
||||
strerror(errno));
|
||||
continue;
|
||||
}
|
||||
construct_state(pfds, FZY_S_ACCEPTED,
|
||||
POLLIN | POLLERR);
|
||||
state[pfds].outbound = n == 0;
|
||||
state[pfds].pp = FZY_PP_CONNECT;
|
||||
state[pfds].ppc = 0;
|
||||
pfd[pfds++].fd = accept_fd;
|
||||
lwsl_notice("new connect accepted\n");
|
||||
continue;
|
||||
}
|
||||
if (pfd[n].revents & POLLIN) {
|
||||
assert(ring_free(&s->in));
|
||||
m = (ring_size(&s->in) - 1) -
|
||||
s->in.head;
|
||||
if (s->in.head == ring_size(&s->in) - 1 &&
|
||||
s->in.tail)
|
||||
m = 1;
|
||||
m = read(pfd[n].fd, s->in.buf + s->in.head, m);
|
||||
// lwsl_notice("read %d\n", m);
|
||||
if (m <= 0)
|
||||
goto drop;
|
||||
s->in.head += m;
|
||||
if (s->in.head == ring_size(&s->in))
|
||||
s->in.head = 0;
|
||||
|
||||
switch (s->type) {
|
||||
case FZY_S_ACCEPTED: /* parse proxy CONNECT */
|
||||
if (handle_accept(n))
|
||||
goto drop;
|
||||
break;
|
||||
case FZY_S_PROXIED:
|
||||
case FZY_S_ONWARD:
|
||||
if (ring_used(&s->in))
|
||||
pfd[s->twin].events |= POLLOUT;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
if (s->in.head == s->in.tail) {
|
||||
s->in.head = s->in.tail = 0;
|
||||
pfd[n].events |= POLLIN;
|
||||
}
|
||||
if (!ring_free(&s->in))
|
||||
pfd[n].events &= ~POLLIN;
|
||||
}
|
||||
if (pfd[n].revents & POLLOUT) {
|
||||
switch (s->type) {
|
||||
case FZY_S_PROXIED:
|
||||
case FZY_S_ONWARD:
|
||||
/*
|
||||
* draw down enough of the partner's
|
||||
* in ring to either exhaust it
|
||||
* or fill an output buffer
|
||||
*/
|
||||
m = fuzz(n, out, sizeof(out));
|
||||
if (m) {
|
||||
m = write(pfd[n].fd, out, m);
|
||||
if (m <= 0)
|
||||
goto drop;
|
||||
} else
|
||||
pfd[n].events &= ~POLLOUT;
|
||||
|
||||
if (ring_free(&state[s->twin].in))
|
||||
pfd[s->twin].events |= POLLIN;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
drop:
|
||||
close_and_remove_fd(n);
|
||||
n--; /* redo this slot */
|
||||
}
|
||||
}
|
||||
|
||||
bail1:
|
||||
lwsl_notice("%s exited cleanly\n", argv[0]);
|
||||
|
||||
#ifndef _WIN32
|
||||
closelog();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue