tinymux/mux/include/interface.h
Stephen Dennis 3113fb15f6 fix(net): Pass 15 A2 — WS preface split, SMTP bounds, zero-listener fail
#1800: Keep DS_NEED_PROTO while bytes are a proper prefix of "GET ";
buffer and replay into WS or telnet once classified; grace timeout
replays any partial preface.

#1802: Cap SMTP read reassembly (64 KiB); 120s overall deadline; surface
queue/flush failures so the singleton channel cannot wedge forever.

#1803: If any listen port was configured but none started, fail
initialize() (clean teardown) instead of running a dead network service.

#1801 (Win32 adoptConnection for @email) remains open — needs engine
initiateConnect on wselect/IOCP.
2026-07-31 05:49:27 -06:00

128 lines
3.6 KiB
C++

/*! \file interface.h
* \brief Driver-side struct definitions: DESC and port_info.
*
* This header provides the full descriptor_data (DESC) struct definition
* and port_info. Engine files that only need forward declarations of DESC
* or program_data, plus telnet/NVT constants, get those from externs.h.
*
* Only include this header in files that dereference DESC members or
* access main_game_ports.
*/
#pragma once
#include "copyright.h"
#ifndef INTERFACE_H
#define INTERFACE_H
struct ws_state;
// Telnet subnegotiation accumulator size. Must be large enough to
// hold the longest subnegotiation payload modern clients send —
// GMCP JSON, MSDP, TTYPE chains, and CHARSET lists can each exceed
// the old 64-byte SBUF_SIZE cap. 4096 matches PennMUSH and covers
// all protocols we currently parse without being wasteful.
//
constexpr size_t TELNET_OPTION_SIZE = 4096;
// Full descriptor_data struct definition.
// Engine files use only the forward declaration from externs.h.
//
struct descriptor_data
{
SocketState ss;
SOCKET socket;
CLinearTimeAbsolute connected_at;
CLinearTimeAbsolute last_time;
int flags;
int retries_left;
int command_count;
int timeout;
dbref player;
UTF8 *output_prefix;
UTF8 *output_suffix;
size_t output_size;
size_t output_tot;
size_t output_lost;
std::deque<std::string> output_queue;
size_t input_size;
size_t input_tot;
size_t input_lost;
bool input_throttled; // hysteresis: dropping input past input_limit
std::deque<std::string> input_queue;
UTF8 *raw_input_buf;
UTF8 *raw_input_at;
size_t nOption;
unsigned char aOption[TELNET_OPTION_SIZE];
// #1131: set when an IAC SB subnegotiation overran aOption and bytes
// were dropped. The accumulated buffer is then a truncated prefix, so
// the completed SB must be discarded rather than parsed. Cleared when
// a new SB begins and when one completes.
//
bool sbOverflow;
int raw_input_state;
int raw_codepoint_state;
size_t raw_codepoint_length;
static constexpr int NVT_TABLE_SIZE = 256;
int nvt_him_state[NVT_TABLE_SIZE];
int nvt_us_state[NVT_TABLE_SIZE];
UTF8 *ttype;
int encoding;
int negotiated_encoding;
bool charset_request_pending;
int width;
int height;
bool gmcp_enabled;
int quota;
struct program_data* program_data;
ws_state *ws; // WebSocket state (nullptr if telnet)
int64_t connlog_id; // SQLite connlog row (0 if not logged)
// #1800: partial WebSocket "GET " preface across TCP read boundaries.
// While DS_NEED_PROTO and len < 4 with a matching prefix of "GET ",
// bytes accumulate here so a split preface is not forced to telnet.
//
char proto_detect_buf[4];
size_t proto_detect_len;
mux_sockaddr address;
UTF8 addr[51];
UTF8 username[11];
UTF8 doing[SIZEOF_DOING_STRING];
};
typedef struct port_info
{
bool fMatched{};
mux_sockaddr msa;
SOCKET socket{};
#ifdef UNIX_SSL
bool fSSL;
#endif
} port_info;
#ifdef UNIX_SSL
extern port_info main_game_ports[MAX_LISTEN_PORTS * 2];
#else
extern port_info main_game_ports[MAX_LISTEN_PORTS];
#endif
extern int num_main_game_ports;
// Connection-refusal log damping (see nospam_connect in net.cpp). Refusing a
// connection still costs a log write, so a connection flood becomes a disk
// flood unless refusal logging is damped.
//
extern bool refusal_log_wanted(const UTF8 *pAddr);
// Per-source connection-rate limit (connect/disconnect churn). See net.cpp.
//
extern bool connect_rate_exceeded(const MUX_SOCKADDR &sa, int *pWait);
extern void connect_rate_charge(const MUX_SOCKADDR &sa);
extern void refusal_log_flush(void);
#endif // !INTERFACE_H