Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit f49f3c83 authored by rswindell's avatar rswindell

Improved telnet option negotiations, specifically, tracking transmitted

requests to allow differentiation between received responses (ACK/NAK) and
remote option requests. This solves the problem with Kermit-95 waiting forever
for a response (ACK or NAK) to its initial option requests (i.e. "Negotiate
About Window Size" and "New Environment Option").
parent 9656f221
......@@ -43,7 +43,6 @@ bool sbbs_t::answer()
char str[MAX_PATH+1],str2[MAX_PATH+1],c;
char tmp[MAX_PATH+1];
char tmp2[MAX_PATH+1];
char buf[64];
int i,l,in;
struct tm tm;
struct in_addr addr;
......@@ -132,15 +131,11 @@ bool sbbs_t::answer()
if(!(telnet_mode&TELNET_MODE_OFF)) {
/* Disable Telnet Terminal Echo */
send_telnet_cmd(TELNET_WILL,TELNET_ECHO);
request_telnet_opt(TELNET_WILL,TELNET_ECHO);
/* Will suppress Go Ahead */
send_telnet_cmd(TELNET_WILL,TELNET_SUP_GA);
request_telnet_opt(TELNET_WILL,TELNET_SUP_GA);
/* Retrieve terminal type from telnet client --RS */
send_telnet_cmd(TELNET_DO,TELNET_TERM_TYPE);
sprintf(buf,"%c%c%c%c%c%c",
TELNET_IAC,TELNET_SB,TELNET_TERM_TYPE,TELNET_TERM_SEND,
TELNET_IAC,TELNET_SE);
putcom(buf,6);
request_telnet_opt(TELNET_DO,TELNET_TERM_TYPE);
}
/* Detect terminal type */
......
......@@ -225,11 +225,9 @@ int sbbs_t::protocol(prot_t* prot, enum XFER_TYPE type
spymsg(msg);
sys_status|=SS_FILEXFER; /* disable spy during file xfer */
/* enable telnet binary transmission in both directions */
if(!(telnet_mode&TELNET_MODE_BIN_RX)) {
send_telnet_cmd(TELNET_DO,TELNET_BINARY);
telnet_mode|=TELNET_MODE_BIN_RX;
}
send_telnet_cmd(TELNET_WILL,TELNET_BINARY);
if(!(telnet_mode&TELNET_MODE_BIN_RX))
request_telnet_opt(TELNET_DO,TELNET_BINARY_TX);
send_telnet_cmd(TELNET_WILL,TELNET_BINARY_TX);
ex_mode=0;
if(prot->misc&PROT_NATIVE)
ex_mode|=EX_NATIVE;
......@@ -239,12 +237,10 @@ int sbbs_t::protocol(prot_t* prot, enum XFER_TYPE type
i=external(cmdline,ex_mode,p);
/* disable telnet binary transmission mode */
send_telnet_cmd(TELNET_WONT,TELNET_BINARY);
send_telnet_cmd(TELNET_WONT,TELNET_BINARY_TX);
/* Got back to Text/NVT mode */
if(telnet_mode&TELNET_MODE_BIN_RX) {
send_telnet_cmd(TELNET_DONT,TELNET_BINARY);
telnet_mode&=~TELNET_MODE_BIN_RX;
}
if(telnet_mode&TELNET_MODE_BIN_RX)
request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX);
sys_status&=~SS_FILEXFER;
if(online==ON_REMOTE)
......
......@@ -1048,13 +1048,18 @@ static BYTE* telnet_interpret(sbbs_t* sbbs, BYTE* inbuf, int inlen,
continue;
}
if(inbuf[i]==TELNET_IAC || sbbs->telnet_cmdlen) {
if(sbbs->telnet_cmdlen<sizeof(sbbs->telnet_cmd))
sbbs->telnet_cmd[sbbs->telnet_cmdlen++]=inbuf[i];
if(sbbs->telnet_cmdlen>=2 && sbbs->telnet_cmd[1]==TELNET_SB) {
uchar command = sbbs->telnet_cmd[1];
uchar option = sbbs->telnet_cmd[2];
if(sbbs->telnet_cmdlen>=2 && command==TELNET_SB) {
if(inbuf[i]==TELNET_SE
&& sbbs->telnet_cmd[sbbs->telnet_cmdlen-2]==TELNET_IAC) {
/* sub-option terminated */
if(sbbs->telnet_cmd[2]==TELNET_TERM_TYPE
if(option==TELNET_TERM_TYPE
&& sbbs->telnet_cmd[3]==TELNET_TERM_IS) {
sprintf(sbbs->terminal,"%.*s",(int)sbbs->telnet_cmdlen-6,sbbs->telnet_cmd+4);
lprintf(LOG_DEBUG,"Node %d %s telnet terminal type: %s"
......@@ -1070,32 +1075,65 @@ static BYTE* telnet_interpret(sbbs_t* sbbs, BYTE* inbuf, int inlen,
lprintf(LOG_DEBUG,"Node %d %s telnet cmd: %s"
,sbbs->cfg.node_num
,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
,telnet_cmd_desc(sbbs->telnet_cmd[2]));
,telnet_cmd_desc(option));
sbbs->telnet_cmdlen=0;
}
else if(sbbs->telnet_cmdlen>=3) {
if(sbbs->telnet_cmd[2]==TELNET_BINARY) {
if(sbbs->telnet_cmd[1]==TELNET_WILL)
sbbs->telnet_mode|=TELNET_MODE_BIN_RX;
else if(sbbs->telnet_cmd[1]==TELNET_WONT)
sbbs->telnet_mode&=~TELNET_MODE_BIN_RX;
else if(sbbs->telnet_cmdlen>=3) { /* telnet option negotiation */
uchar request = sbbs->telnet_option_request[option];
if(command==telnet_opt_ack(request) || command==telnet_opt_nak(request)) {
/* response to request */
if(startup->options&BBS_OPT_DEBUG_TELNET)
lprintf(LOG_DEBUG,"Node %d %s telnet response: %s %s"
,sbbs->cfg.node_num
,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
,telnet_cmd_desc(command)
,telnet_opt_desc(option));
if(command==TELNET_WILL && option==TELNET_TERM_TYPE) {
char buf[64];
sprintf(buf,"%c%c%c%c%c%c"
,TELNET_IAC,TELNET_SB
,TELNET_TERM_TYPE,TELNET_TERM_SEND
,TELNET_IAC,TELNET_SE);
sbbs->putcom(buf,6);
}
if(option==TELNET_BINARY_TX) {
if(command==TELNET_WILL)
sbbs->telnet_mode|=TELNET_MODE_BIN_RX;
else if(command==TELNET_WONT)
sbbs->telnet_mode&=~TELNET_MODE_BIN_RX;
}
sbbs->telnet_option_request[option] = 0;
}
if(sbbs->telnet_cmd[2]==TELNET_ECHO) {
if(sbbs->telnet_cmd[1]==TELNET_DO)
sbbs->telnet_mode|=TELNET_MODE_ECHO;
else if(sbbs->telnet_cmd[1]==TELNET_DONT) {
sbbs->telnet_mode&=~TELNET_MODE_ECHO;
if(!(sbbs->telnet_mode&TELNET_MODE_GATE))
sbbs->send_telnet_cmd(TELNET_WILL,TELNET_ECHO);
else { /* not a response */
if(startup->options&BBS_OPT_DEBUG_TELNET)
lprintf(LOG_DEBUG,"Node %d %s telnet cmd: %s %s"
,sbbs->cfg.node_num
,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
,telnet_cmd_desc(command)
,telnet_opt_desc(option));
switch(option) {
case TELNET_BINARY_TX:
case TELNET_ECHO:
case TELNET_TERM_TYPE:
case TELNET_SUP_GA:
break;
default: /* ACK unsupported remote options */
if(command==TELNET_WILL || command==TELNET_WONT)
sbbs->send_telnet_cmd(telnet_opt_ack(command),option);
else if(command==TELNET_DO) /* NAK unsupported local options */
sbbs->send_telnet_cmd(telnet_opt_nak(command),option);
break;
}
}
if(startup->options&BBS_OPT_DEBUG_TELNET)
lprintf(LOG_DEBUG,"Node %d %s telnet cmd: %s %s"
,sbbs->cfg.node_num
,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
,telnet_cmd_desc(sbbs->telnet_cmd[1])
,telnet_opt_desc(sbbs->telnet_cmd[2]));
sbbs->telnet_cmdlen=0;
}
if(sbbs->telnet_mode&TELNET_MODE_GATE) // Pass-through commads
outbuf[outlen++]=inbuf[i];
......@@ -1130,6 +1168,12 @@ void sbbs_t::send_telnet_cmd(uchar cmd, uchar opt)
}
}
void sbbs_t::request_telnet_opt(uchar cmd, uchar opt)
{
telnet_option_request[opt]=cmd; /* save request */
send_telnet_cmd(cmd,opt);
}
void input_thread(void *arg)
{
BYTE inbuf[4000];
......@@ -2198,9 +2242,12 @@ sbbs_t::sbbs_t(ushort node_num, DWORD addr, char* name, SOCKET sd,
uselect_total = 0;
lbuflen = 0;
connection="Telnet";
memset(telnet_option_request,0,sizeof(telnet_option_request));
telnet_cmdlen=0;
telnet_mode=0;
telnet_last_rxch=0;
sys_status=lncntr=tos=criterrs=keybufbot=keybuftop=lbuflen=slcnt=0L;
curatr=LIGHTGRAY;
attr_sp=0; /* attribute stack pointer */
......
......@@ -110,10 +110,13 @@
#ifdef SBBS
#include "text.h"
#endif
/* xpdev */
#include "genwrap.h"
#include "dirwrap.h"
#include "filewrap.h"
#include "sockwrap.h"
#include "smblib.h"
#include "ars_defs.h"
#include "scfgdefs.h"
......@@ -173,7 +176,10 @@ public:
void hangup(void); // Hangup modem
uchar telnet_option_request[0x100];
void send_telnet_cmd(uchar cmd, uchar opt);
void request_telnet_opt(uchar cmd, uchar opt);
uchar telnet_cmd[64];
uint telnet_cmdlen;
ulong telnet_mode;
......
......@@ -135,11 +135,10 @@ void sbbs_t::telnet_gate(char* destaddr, ulong mode)
}
/* This is required for gating to Unix telnetd */
send_telnet_cmd(TELNET_DONT,TELNET_TERM_TYPE); // Re-negotiation of terminal type
request_telnet_opt(TELNET_DONT,TELNET_TERM_TYPE); // Re-negotiation of terminal type
/* Text/NVT mode by default */
send_telnet_cmd(TELNET_DONT,TELNET_BINARY);
telnet_mode&=~TELNET_MODE_BIN_RX;
request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX);
while(online) {
if(!(mode&TG_NOCHKTIME))
......
......@@ -8,7 +8,7 @@
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -125,3 +125,25 @@ const char* DLLCALL telnet_opt_desc(uchar opt)
sprintf(unknown,"%d",opt);
return(unknown);
}
const uchar DLLCALL telnet_opt_ack(uchar cmd)
{
switch(cmd) {
case TELNET_DO: return TELNET_WILL;
case TELNET_DONT: return TELNET_WONT;
case TELNET_WILL: return TELNET_DO;
case TELNET_WONT: return TELNET_DONT;
}
return 0;
}
const uchar DLLCALL telnet_opt_nak(uchar cmd)
{
switch(cmd) {
case TELNET_DO: return TELNET_WONT;
case TELNET_DONT: return TELNET_WILL;
case TELNET_WILL: return TELNET_DONT;
case TELNET_WONT: return TELNET_DO;
}
return 0;
}
......@@ -8,7 +8,7 @@
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html *
* Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -38,13 +38,15 @@
#ifndef _TELNET_H
#define _TELNET_H
#include "gen_defs.h" /* uchar */
/* commands */
#define TELNET_IAC 255 /* Interpret as command */
#define TELNET_DONT 254 /* Don't do option */
#define TELNET_DO 253 /* Do option */
#define TELNET_WONT 252 /* Won't do option */
#define TELNET_WILL 251 /* Will do option */
#define TELNET_IAC 255 /* 0xff - Interpret as command */
#define TELNET_DONT 254 /* 0xfe - Don't do option */
#define TELNET_DO 253 /* 0xfd - Do option */
#define TELNET_WONT 252 /* 0xfc - Won't do option */
#define TELNET_WILL 251 /* 0xfb - Will do option */
#define TELNET_SB 250 /* sub-negotiation */
#define TELNET_GA 249 /* Go ahead */
......@@ -62,7 +64,7 @@
/* options */
enum {
TELNET_BINARY
TELNET_BINARY_TX
,TELNET_ECHO
,TELNET_RECONN
,TELNET_SUP_GA /* suppress go ahead */
......@@ -148,6 +150,8 @@ extern "C" {
DLLEXPORT const char* DLLCALL telnet_cmd_desc(uchar cmd);
DLLEXPORT const char* DLLCALL telnet_opt_desc(uchar opt);
DLLEXPORT const uchar DLLCALL telnet_opt_ack(uchar cmd);
DLLEXPORT const uchar DLLCALL telnet_opt_nak(uchar cmd);
#ifdef __cplusplus
}
......
......@@ -1026,10 +1026,8 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
rio_abortable=rio_abortable_save; // Restore abortable state
/* Got back to Text/NVT mode */
if(telnet_mode&TELNET_MODE_BIN_RX) {
send_telnet_cmd(TELNET_DONT,TELNET_BINARY);
telnet_mode&=~TELNET_MODE_BIN_RX;
}
if(telnet_mode&TELNET_MODE_BIN_RX)
request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX);
}
// lprintf("%s returned %d",realcmdline, retval);
......@@ -1886,10 +1884,8 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
rio_abortable=rio_abortable_save; // Restore abortable state
/* Got back to Text/NVT mode */
if(telnet_mode&TELNET_MODE_BIN_RX) {
send_telnet_cmd(TELNET_DONT,TELNET_BINARY);
telnet_mode&=~TELNET_MODE_BIN_RX;
}
if(telnet_mode&TELNET_MODE_BIN_RX)
request_telnet_opt(TELNET_DONT,TELNET_BINARY_TX);
}
close(err_pipe[0]);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment