Major destabilisation, phase 2. This time it's the backends' turn:

each backend now stores all its internal variables in a big struct,
and each backend function gets a pointer to this struct passed to
it. This still isn't the end of the work - lots of subsidiary things
still use globals, notably all the cipher and compressor modules and
the X11 forwarding authentication stuff. But ssh.c itself has now
been transformed, and that was the really painful bit, so from here
on it all ought to be a sequence of much smaller and simpler pieces
of work.

[originally from svn r2127]
This commit is contained in:
Simon Tatham 2002-10-25 11:30:33 +00:00
Родитель c2e37334a5
Коммит 72ff571148
14 изменённых файлов: 2627 добавлений и 2399 удалений

42
ldisc.c
Просмотреть файл

@ -13,10 +13,12 @@
#define ECHOING (cfg.localecho == LD_YES || \
(cfg.localecho == LD_BACKEND && \
(back->ldisc(LD_ECHO) || term_ldisc(term, LD_ECHO))))
(back->ldisc(backhandle, LD_ECHO) || \
term_ldisc(term, LD_ECHO))))
#define EDITING (cfg.localedit == LD_YES || \
(cfg.localedit == LD_BACKEND && \
(back->ldisc(LD_EDIT) || term_ldisc(term, LD_EDIT))))
(back->ldisc(backhandle, LD_EDIT) || \
term_ldisc(term, LD_EDIT))))
static void c_write(char *buf, int len)
{
@ -138,7 +140,7 @@ void ldisc_send(char *buf, int len, int interactive)
bsb(plen(term_buf[term_buflen - 1]));
term_buflen--;
}
back->special(TS_EL);
back->special(backhandle, TS_EL);
/*
* We don't send IP, SUSP or ABORT if the user has
* configured telnet specials off! This breaks
@ -147,11 +149,11 @@ void ldisc_send(char *buf, int len, int interactive)
if (!cfg.telnet_keyboard)
goto default_case;
if (c == CTRL('C'))
back->special(TS_IP);
back->special(backhandle, TS_IP);
if (c == CTRL('Z'))
back->special(TS_SUSP);
back->special(backhandle, TS_SUSP);
if (c == CTRL('\\'))
back->special(TS_ABORT);
back->special(backhandle, TS_ABORT);
break;
case CTRL('R'): /* redraw line */
if (ECHOING) {
@ -166,9 +168,9 @@ void ldisc_send(char *buf, int len, int interactive)
break;
case CTRL('D'): /* logout or send */
if (term_buflen == 0) {
back->special(TS_EOF);
back->special(backhandle, TS_EOF);
} else {
back->send(term_buf, term_buflen);
back->send(backhandle, term_buf, term_buflen);
term_buflen = 0;
}
break;
@ -204,13 +206,13 @@ void ldisc_send(char *buf, int len, int interactive)
/* FALLTHROUGH */
case KCTRL('M'): /* send with newline */
if (term_buflen > 0)
back->send(term_buf, term_buflen);
back->send(backhandle, term_buf, term_buflen);
if (cfg.protocol == PROT_RAW)
back->send("\r\n", 2);
back->send(backhandle, "\r\n", 2);
else if (cfg.protocol == PROT_TELNET && cfg.telnet_newline)
back->special(TS_EOL);
back->special(backhandle, TS_EOL);
else
back->send("\r", 1);
back->send(backhandle, "\r", 1);
if (ECHOING)
c_write("\r\n", 2);
term_buflen = 0;
@ -232,7 +234,7 @@ void ldisc_send(char *buf, int len, int interactive)
}
} else {
if (term_buflen != 0) {
back->send(term_buf, term_buflen);
back->send(backhandle, term_buf, term_buflen);
while (term_buflen > 0) {
bsb(plen(term_buf[term_buflen - 1]));
term_buflen--;
@ -245,33 +247,33 @@ void ldisc_send(char *buf, int len, int interactive)
switch (buf[0]) {
case CTRL('M'):
if (cfg.protocol == PROT_TELNET && cfg.telnet_newline)
back->special(TS_EOL);
back->special(backhandle, TS_EOL);
else
back->send("\r", 1);
back->send(backhandle, "\r", 1);
break;
case CTRL('?'):
case CTRL('H'):
if (cfg.telnet_keyboard) {
back->special(TS_EC);
back->special(backhandle, TS_EC);
break;
}
case CTRL('C'):
if (cfg.telnet_keyboard) {
back->special(TS_IP);
back->special(backhandle, TS_IP);
break;
}
case CTRL('Z'):
if (cfg.telnet_keyboard) {
back->special(TS_SUSP);
back->special(backhandle, TS_SUSP);
break;
}
default:
back->send(buf, len);
back->send(backhandle, buf, len);
break;
}
} else
back->send(buf, len);
back->send(backhandle, buf, len);
}
}
}

25
plink.c
Просмотреть файл

@ -529,7 +529,8 @@ int main(int argc, char **argv)
int nodelay = cfg.tcp_nodelay &&
(GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR);
error = back->init(NULL, cfg.host, cfg.port, &realhost, nodelay);
error = back->init(NULL, &backhandle, cfg.host, cfg.port,
&realhost, nodelay);
if (error) {
fprintf(stderr, "Unable to open connection:\n%s", error);
return 1;
@ -585,7 +586,7 @@ int main(int argc, char **argv)
while (1) {
int n;
if (!sending && back->sendok()) {
if (!sending && back->sendok(backhandle)) {
/*
* Create a separate thread to read from stdin. This is
* a total pain, but I can't find another way to do it:
@ -677,11 +678,11 @@ int main(int argc, char **argv)
} else if (n == 1) {
reading = 0;
noise_ultralight(idata.len);
if (connopen && back->socket() != NULL) {
if (connopen && back->socket(backhandle) != NULL) {
if (idata.len > 0) {
back->send(idata.buffer, idata.len);
back->send(backhandle, idata.buffer, idata.len);
} else {
back->special(TS_EOF);
back->special(backhandle, TS_EOF);
}
}
} else if (n == 2) {
@ -693,8 +694,8 @@ int main(int argc, char **argv)
bufchain_consume(&stdout_data, odata.lenwritten);
if (bufchain_size(&stdout_data) > 0)
try_output(0);
if (connopen && back->socket() != NULL) {
back->unthrottle(bufchain_size(&stdout_data) +
if (connopen && back->socket(backhandle) != NULL) {
back->unthrottle(backhandle, bufchain_size(&stdout_data) +
bufchain_size(&stderr_data));
}
} else if (n == 3) {
@ -706,22 +707,22 @@ int main(int argc, char **argv)
bufchain_consume(&stderr_data, edata.lenwritten);
if (bufchain_size(&stderr_data) > 0)
try_output(1);
if (connopen && back->socket() != NULL) {
back->unthrottle(bufchain_size(&stdout_data) +
if (connopen && back->socket(backhandle) != NULL) {
back->unthrottle(backhandle, bufchain_size(&stdout_data) +
bufchain_size(&stderr_data));
}
}
if (!reading && back->sendbuffer() < MAX_STDIN_BACKLOG) {
if (!reading && back->sendbuffer(backhandle) < MAX_STDIN_BACKLOG) {
SetEvent(idata.eventback);
reading = 1;
}
if ((!connopen || back->socket() == NULL) &&
if ((!connopen || back->socket(backhandle) == NULL) &&
bufchain_size(&stdout_data) == 0 &&
bufchain_size(&stderr_data) == 0)
break; /* we closed the connection */
}
WSACleanup();
exitcode = back->exitcode();
exitcode = back->exitcode(backhandle);
if (exitcode < 0) {
fprintf(stderr, "Remote process exit code unavailable\n");
exitcode = 1; /* this is an error condition */

Просмотреть файл

@ -177,7 +177,7 @@ static int pfd_accepting(Plug p, void *sock)
return err != NULL;
}
pr->c = new_sock_channel(s);
pr->c = new_sock_channel(backhandle, s);
strcpy(pr->hostname, org->hostname);
pr->port = org->port;
@ -192,7 +192,8 @@ static int pfd_accepting(Plug p, void *sock)
return 1;
} else {
/* asks to forward to the specified host/port for this */
ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
ssh_send_port_open(backhandle, pr->c, pr->hostname,
pr->port, "forwarding");
}
return 0;

10
psftp.c
Просмотреть файл

@ -1610,7 +1610,7 @@ int sftp_recvdata(char *buf, int len)
}
int sftp_senddata(char *buf, int len)
{
back->send((unsigned char *) buf, len);
back->send(backhandle, (unsigned char *) buf, len);
return 1;
}
@ -1621,7 +1621,7 @@ static void ssh_sftp_init(void)
{
if (sftp_ssh_socket == INVALID_SOCKET)
return;
while (!back->sendok()) {
while (!back->sendok(backhandle)) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sftp_ssh_socket, &readfds);
@ -1822,7 +1822,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
back = &ssh_backend;
err = back->init(NULL, cfg.host, cfg.port, &realhost, 0);
err = back->init(NULL, &backhandle, cfg.host, cfg.port, &realhost, 0);
if (err != NULL) {
fprintf(stderr, "ssh_init: %s\n", err);
return 1;
@ -1921,9 +1921,9 @@ int main(int argc, char *argv[])
do_sftp(mode, modeflags, batchfile);
if (back != NULL && back->socket() != NULL) {
if (back != NULL && back->socket(backhandle) != NULL) {
char ch;
back->special(TS_EOF);
back->special(backhandle, TS_EOF);
sftp_recvdata(&ch, 1);
}
WSACleanup();

24
putty.h
Просмотреть файл

@ -188,27 +188,28 @@ enum {
};
struct backend_tag {
char *(*init) (void *frontend_handle,
char *(*init) (void *frontend_handle, void **backend_handle,
char *host, int port, char **realhost, int nodelay);
/* back->send() returns the current amount of buffered data. */
int (*send) (char *buf, int len);
int (*send) (void *handle, char *buf, int len);
/* back->sendbuffer() does the same thing but without attempting a send */
int (*sendbuffer) (void);
void (*size) (int width, int height);
void (*special) (Telnet_Special code);
Socket(*socket) (void);
int (*exitcode) (void);
int (*sendok) (void);
int (*ldisc) (int);
int (*sendbuffer) (void *handle);
void (*size) (void *handle, int width, int height);
void (*special) (void *handle, Telnet_Special code);
Socket(*socket) (void *handle);
int (*exitcode) (void *handle);
int (*sendok) (void *handle);
int (*ldisc) (void *handle, int);
/*
* back->unthrottle() tells the back end that the front end
* buffer is clearing.
*/
void (*unthrottle) (int);
void (*unthrottle) (void *handle, int);
int default_port;
};
GLOBAL Backend *back;
GLOBAL void *backhandle;
extern struct backend_list {
int protocol;
@ -488,6 +489,9 @@ void term_copyall(Terminal *);
void term_reconfig(Terminal *);
void term_seen_key_event(Terminal *);
int from_backend(void *, int is_stderr, char *data, int len);
void term_provide_resize_fn(Terminal *term,
void (*resize_fn)(void *, int, int),
void *resize_ctx);
/*
* Exports from logging.c.

89
raw.c
Просмотреть файл

@ -13,24 +13,31 @@
#define RAW_MAX_BACKLOG 4096
static Socket s = NULL;
static int raw_bufsize;
static void *frontend;
typedef struct raw_backend_data {
const struct plug_function_table *fn;
/* the above field _must_ be first in the structure */
static void raw_size(int width, int height);
Socket s;
int bufsize;
void *frontend;
} *Raw;
static void c_write(char *buf, int len)
static void raw_size(void *handle, int width, int height);
static void c_write(Raw raw, char *buf, int len)
{
int backlog = from_backend(frontend, 0, buf, len);
sk_set_frozen(s, backlog > RAW_MAX_BACKLOG);
int backlog = from_backend(raw->frontend, 0, buf, len);
sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);
}
static int raw_closing(Plug plug, char *error_msg, int error_code,
int calling_back)
{
if (s) {
sk_close(s);
s = NULL;
Raw raw = (Raw) plug;
if (raw->s) {
sk_close(raw->s);
raw->s = NULL;
}
if (error_msg) {
/* A socket error has occurred. */
@ -42,13 +49,15 @@ static int raw_closing(Plug plug, char *error_msg, int error_code,
static int raw_receive(Plug plug, int urgent, char *data, int len)
{
c_write(data, len);
Raw raw = (Raw) plug;
c_write(raw, data, len);
return 1;
}
static void raw_sent(Plug plug, int bufsize)
{
raw_bufsize = bufsize;
Raw raw = (Raw) plug;
raw->bufsize = bufsize;
}
/*
@ -59,19 +68,24 @@ static void raw_sent(Plug plug, int bufsize)
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
static char *raw_init(void *frontend_handle, char *host, int port,
char **realhost, int nodelay)
static char *raw_init(void *frontend_handle, void **backend_handle,
char *host, int port, char **realhost, int nodelay)
{
static struct plug_function_table fn_table = {
static const struct plug_function_table fn_table = {
raw_closing,
raw_receive,
raw_sent
}, *fn_table_ptr = &fn_table;
};
SockAddr addr;
char *err;
Raw raw;
frontend = frontend_handle;
raw = smalloc(sizeof(*raw));
raw->fn = &fn_table;
raw->s = NULL;
*backend_handle = raw;
raw->frontend = frontend_handle;
/*
* Try to find host.
@ -97,8 +111,8 @@ static char *raw_init(void *frontend_handle, char *host, int port,
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
logevent(buf);
}
s = new_connection(addr, *realhost, port, 0, 1, nodelay, &fn_table_ptr);
if ((err = sk_socket_error(s)))
raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, (Plug) raw);
if ((err = sk_socket_error(raw->s)))
return err;
sk_addr_free(addr);
@ -109,28 +123,31 @@ static char *raw_init(void *frontend_handle, char *host, int port,
/*
* Called to send data down the raw connection.
*/
static int raw_send(char *buf, int len)
static int raw_send(void *handle, char *buf, int len)
{
if (s == NULL)
Raw raw = (Raw) handle;
if (raw->s == NULL)
return 0;
raw_bufsize = sk_write(s, buf, len);
raw->bufsize = sk_write(raw->s, buf, len);
return raw_bufsize;
return raw->bufsize;
}
/*
* Called to query the current socket sendability status.
*/
static int raw_sendbuffer(void)
static int raw_sendbuffer(void *handle)
{
return raw_bufsize;
Raw raw = (Raw) handle;
return raw->bufsize;
}
/*
* Called to set the size of the window
*/
static void raw_size(int width, int height)
static void raw_size(void *handle, int width, int height)
{
/* Do nothing! */
return;
@ -139,35 +156,37 @@ static void raw_size(int width, int height)
/*
* Send raw special codes.
*/
static void raw_special(Telnet_Special code)
static void raw_special(void *handle, Telnet_Special code)
{
/* Do nothing! */
return;
}
static Socket raw_socket(void)
static Socket raw_socket(void *handle)
{
return s;
Raw raw = (Raw) handle;
return raw->s;
}
static int raw_sendok(void)
static int raw_sendok(void *handle)
{
return 1;
}
static void raw_unthrottle(int backlog)
static void raw_unthrottle(void *handle, int backlog)
{
sk_set_frozen(s, backlog > RAW_MAX_BACKLOG);
Raw raw = (Raw) handle;
sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);
}
static int raw_ldisc(int option)
static int raw_ldisc(void *handle, int option)
{
if (option == LD_EDIT || option == LD_ECHO)
return 1;
return 0;
}
static int raw_exitcode(void)
static int raw_exitcode(void *handle)
{
/* Exit codes are a meaningless concept in the Raw protocol */
return 0;

132
rlogin.c
Просмотреть файл

@ -14,25 +14,31 @@
#define RLOGIN_MAX_BACKLOG 4096
static Socket s = NULL;
static int rlogin_bufsize;
static int rlogin_term_width, rlogin_term_height;
static void *frontend;
typedef struct rlogin_tag {
const struct plug_function_table *fn;
/* the above field _must_ be first in the structure */
static void rlogin_size(int width, int height);
Socket s;
int bufsize;
int term_width, term_height;
void *frontend;
} *Rlogin;
static void c_write(char *buf, int len)
static void rlogin_size(void *handle, int width, int height);
static void c_write(Rlogin rlogin, char *buf, int len)
{
int backlog = from_backend(frontend, 0, buf, len);
sk_set_frozen(s, backlog > RLOGIN_MAX_BACKLOG);
int backlog = from_backend(rlogin->frontend, 0, buf, len);
sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG);
}
static int rlogin_closing(Plug plug, char *error_msg, int error_code,
int calling_back)
{
if (s) {
sk_close(s);
s = NULL;
Rlogin rlogin = (Rlogin) plug;
if (rlogin->s) {
sk_close(rlogin->s);
rlogin->s = NULL;
}
if (error_msg) {
/* A socket error has occurred. */
@ -44,13 +50,14 @@ static int rlogin_closing(Plug plug, char *error_msg, int error_code,
static int rlogin_receive(Plug plug, int urgent, char *data, int len)
{
Rlogin rlogin = (Rlogin) plug;
if (urgent == 2) {
char c;
c = *data++;
len--;
if (c == '\x80')
rlogin_size(rlogin_term_width, rlogin_term_height);
rlogin_size(rlogin, rlogin->term_width, rlogin->term_height);
/*
* We should flush everything (aka Telnet SYNCH) if we see
* 0x02, and we should turn off and on _local_ flow control
@ -72,14 +79,15 @@ static int rlogin_receive(Plug plug, int urgent, char *data, int len)
firstbyte = 0;
}
if (len > 0)
c_write(data, len);
c_write(rlogin, data, len);
}
return 1;
}
static void rlogin_sent(Plug plug, int bufsize)
{
rlogin_bufsize = bufsize;
Rlogin rlogin = (Rlogin) plug;
rlogin->bufsize = bufsize;
}
/*
@ -90,21 +98,25 @@ static void rlogin_sent(Plug plug, int bufsize)
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
static char *rlogin_init(void *frontend_handle,
static char *rlogin_init(void *frontend_handle, void **backend_handle,
char *host, int port, char **realhost, int nodelay)
{
static struct plug_function_table fn_table = {
static const struct plug_function_table fn_table = {
rlogin_closing,
rlogin_receive,
rlogin_sent
}, *fn_table_ptr = &fn_table;
};
SockAddr addr;
char *err;
Rlogin rlogin;
frontend = frontend_handle;
rlogin_term_width = cfg.width;
rlogin_term_height = cfg.height;
rlogin = smalloc(sizeof(*rlogin));
rlogin->fn = &fn_table;
rlogin->s = NULL;
rlogin->frontend = frontend_handle;
rlogin->term_width = cfg.width;
rlogin->term_height = cfg.height;
*backend_handle = rlogin;
/*
* Try to find host.
@ -130,8 +142,9 @@ static char *rlogin_init(void *frontend_handle,
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
logevent(buf);
}
s = new_connection(addr, *realhost, port, 1, 0, nodelay, &fn_table_ptr);
if ((err = sk_socket_error(s)))
rlogin->s = new_connection(addr, *realhost, port, 1, 0,
nodelay, (Plug) rlogin);
if ((err = sk_socket_error(rlogin->s)))
return err;
sk_addr_free(addr);
@ -143,16 +156,16 @@ static char *rlogin_init(void *frontend_handle,
{
char z = 0;
char *p;
sk_write(s, &z, 1);
sk_write(s, cfg.localusername, strlen(cfg.localusername));
sk_write(s, &z, 1);
sk_write(s, cfg.username, strlen(cfg.username));
sk_write(s, &z, 1);
sk_write(s, cfg.termtype, strlen(cfg.termtype));
sk_write(s, "/", 1);
sk_write(rlogin->s, &z, 1);
sk_write(rlogin->s, cfg.localusername, strlen(cfg.localusername));
sk_write(rlogin->s, &z, 1);
sk_write(rlogin->s, cfg.username, strlen(cfg.username));
sk_write(rlogin->s, &z, 1);
sk_write(rlogin->s, cfg.termtype, strlen(cfg.termtype));
sk_write(rlogin->s, "/", 1);
for (p = cfg.termspeed; isdigit(*p); p++);
sk_write(s, cfg.termspeed, p - cfg.termspeed);
rlogin_bufsize = sk_write(s, &z, 1);
sk_write(rlogin->s, cfg.termspeed, p - cfg.termspeed);
rlogin->bufsize = sk_write(rlogin->s, &z, 1);
}
return NULL;
@ -161,76 +174,85 @@ static char *rlogin_init(void *frontend_handle,
/*
* Called to send data down the rlogin connection.
*/
static int rlogin_send(char *buf, int len)
static int rlogin_send(void *handle, char *buf, int len)
{
if (s == NULL)
Rlogin rlogin = (Rlogin) handle;
if (rlogin->s == NULL)
return 0;
rlogin_bufsize = sk_write(s, buf, len);
rlogin->bufsize = sk_write(rlogin->s, buf, len);
return rlogin_bufsize;
return rlogin->bufsize;
}
/*
* Called to query the current socket sendability status.
*/
static int rlogin_sendbuffer(void)
static int rlogin_sendbuffer(void *handle)
{
return rlogin_bufsize;
Rlogin rlogin = (Rlogin) handle;
return rlogin->bufsize;
}
/*
* Called to set the size of the window
*/
static void rlogin_size(int width, int height)
static void rlogin_size(void *handle, int width, int height)
{
Rlogin rlogin = (Rlogin) handle;
char b[12] = { '\xFF', '\xFF', 0x73, 0x73, 0, 0, 0, 0, 0, 0, 0, 0 };
rlogin_term_width = width;
rlogin_term_height = height;
rlogin->term_width = width;
rlogin->term_height = height;
if (s == NULL)
if (rlogin->s == NULL)
return;
b[6] = rlogin_term_width >> 8;
b[7] = rlogin_term_width & 0xFF;
b[4] = rlogin_term_height >> 8;
b[5] = rlogin_term_height & 0xFF;
rlogin_bufsize = sk_write(s, b, 12);
b[6] = rlogin->term_width >> 8;
b[7] = rlogin->term_width & 0xFF;
b[4] = rlogin->term_height >> 8;
b[5] = rlogin->term_height & 0xFF;
rlogin->bufsize = sk_write(rlogin->s, b, 12);
return;
}
/*
* Send rlogin special codes.
*/
static void rlogin_special(Telnet_Special code)
static void rlogin_special(void *handle, Telnet_Special code)
{
/* Do nothing! */
return;
}
static Socket rlogin_socket(void)
static Socket rlogin_socket(void *handle)
{
return s;
Rlogin rlogin = (Rlogin) handle;
return rlogin->s;
}
static int rlogin_sendok(void)
static int rlogin_sendok(void *handle)
{
Rlogin rlogin = (Rlogin) handle;
return 1;
}
static void rlogin_unthrottle(int backlog)
static void rlogin_unthrottle(void *handle, int backlog)
{
sk_set_frozen(s, backlog > RLOGIN_MAX_BACKLOG);
Rlogin rlogin = (Rlogin) handle;
sk_set_frozen(rlogin->s, backlog > RLOGIN_MAX_BACKLOG);
}
static int rlogin_ldisc(int option)
static int rlogin_ldisc(void *handle, int option)
{
Rlogin rlogin = (Rlogin) handle;
return 0;
}
static int rlogin_exitcode(void)
static int rlogin_exitcode(void *handle)
{
Rlogin rlogin = (Rlogin) handle;
/* If we ever implement RSH, we'll probably need to do this properly */
return 0;
}

54
scp.c
Просмотреть файл

@ -408,7 +408,7 @@ static void ssh_scp_init(void)
{
if (scp_ssh_socket == INVALID_SOCKET)
return;
while (!back->sendok()) {
while (!back->sendok(backhandle)) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(scp_ssh_socket, &readfds);
@ -416,7 +416,7 @@ static void ssh_scp_init(void)
return; /* doom */
select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
}
using_sftp = !ssh_fallback_cmd;
using_sftp = !ssh_fallback_cmd(backhandle);
}
/*
@ -434,9 +434,9 @@ static void bump(char *fmt, ...)
tell_str(stderr, str);
errs++;
if (back != NULL && back->socket() != NULL) {
if (back != NULL && back->socket(backhandle) != NULL) {
char ch;
back->special(TS_EOF);
back->special(backhandle, TS_EOF);
ssh_scp_recv(&ch, 1);
}
@ -565,7 +565,7 @@ static void do_cmd(char *host, char *user, char *cmd)
back = &ssh_backend;
err = back->init(NULL, cfg.host, cfg.port, &realhost, 0);
err = back->init(NULL, &backhandle, cfg.host, cfg.port, &realhost, 0);
if (err != NULL)
bump("ssh_init: %s", err);
ssh_scp_init();
@ -712,7 +712,7 @@ int sftp_recvdata(char *buf, int len)
}
int sftp_senddata(char *buf, int len)
{
back->send((unsigned char *) buf, len);
back->send(backhandle, (unsigned char *) buf, len);
return 1;
}
@ -824,7 +824,7 @@ void scp_source_setup(char *target, int shouldbedir)
if (!fxp_init()) {
tell_user(stderr, "unable to initialise SFTP: %s", fxp_error());
errs++;
return 1;
return;
}
if (!fxp_stat(target, &attrs) ||
@ -850,8 +850,8 @@ int scp_send_errmsg(char *str)
if (using_sftp) {
/* do nothing; we never need to send our errors to the server */
} else {
back->send("\001", 1); /* scp protocol error prefix */
back->send(str, strlen(str));
back->send(backhandle, "\001", 1);/* scp protocol error prefix */
back->send(backhandle, str, strlen(str));
}
return 0; /* can't fail */
}
@ -866,7 +866,7 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime)
} else {
char buf[80];
sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime);
back->send(buf, strlen(buf));
back->send(backhandle, buf, strlen(buf));
return response();
}
}
@ -894,9 +894,9 @@ int scp_send_filename(char *name, unsigned long size, int modes)
} else {
char buf[40];
sprintf(buf, "C%04o %lu ", modes, size);
back->send(buf, strlen(buf));
back->send(name, strlen(name));
back->send("\n", 1);
back->send(backhandle, buf, strlen(buf));
back->send(backhandle, name, strlen(name));
back->send(backhandle, "\n", 1);
return response();
}
}
@ -915,7 +915,7 @@ int scp_send_filedata(char *data, int len)
scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len);
return 0;
} else {
int bufsize = back->send(data, len);
int bufsize = back->send(backhandle, data, len);
/*
* If the network transfer is backing up - that is, the
@ -926,7 +926,7 @@ int scp_send_filedata(char *data, int len)
while (bufsize > MAX_SCP_BUFSIZE) {
if (!scp_process_network_event())
return 1;
bufsize = back->sendbuffer();
bufsize = back->sendbuffer(backhandle);
}
return 0;
@ -953,7 +953,7 @@ int scp_send_finish(void)
scp_has_times = 0;
return 0;
} else {
back->send("", 1);
back->send(backhandle, "", 1);
return response();
}
}
@ -1010,9 +1010,9 @@ int scp_send_dirname(char *name, int modes)
} else {
char buf[40];
sprintf(buf, "D%04o 0 ", modes);
back->send(buf, strlen(buf));
back->send(name, strlen(name));
back->send("\n", 1);
back->send(backhandle, buf, strlen(buf));
back->send(backhandle, name, strlen(name));
back->send(backhandle, "\n", 1);
return response();
}
}
@ -1023,7 +1023,7 @@ int scp_send_enddir(void)
sfree(scp_sftp_remotepath);
return 0;
} else {
back->send("E\n", 2);
back->send(backhandle, "E\n", 2);
return response();
}
}
@ -1118,7 +1118,7 @@ int scp_sink_setup(char *source, int preserve, int recursive)
int scp_sink_init(void)
{
if (!using_sftp) {
back->send("", 1);
back->send(backhandle, "", 1);
}
return 0;
}
@ -1404,14 +1404,14 @@ int scp_get_sink_action(struct scp_sink_action *act)
case '\02': /* fatal error */
bump("%s", act->buf);
case 'E':
back->send("", 1);
back->send(backhandle, "", 1);
act->action = SCP_SINK_ENDDIR;
return 0;
case 'T':
if (sscanf(act->buf, "%ld %*d %ld %*d",
&act->mtime, &act->atime) == 2) {
act->settime = 1;
back->send("", 1);
back->send(backhandle, "", 1);
continue; /* go round again */
}
bump("Protocol error: Illegal time format");
@ -1455,7 +1455,7 @@ int scp_accept_filexfer(void)
sfree(scp_sftp_currentname);
return 0;
} else {
back->send("", 1);
back->send(backhandle, "", 1);
return 0; /* can't fail */
}
}
@ -1487,7 +1487,7 @@ int scp_finish_filerecv(void)
fxp_close(scp_sftp_filehandle);
return 0;
} else {
back->send("", 1);
back->send(backhandle, "", 1);
return response();
}
}
@ -2234,9 +2234,9 @@ int main(int argc, char *argv[])
tolocal(argc, argv);
}
if (back != NULL && back->socket() != NULL) {
if (back != NULL && back->socket(backhandle) != NULL) {
char ch;
back->special(TS_EOF);
back->special(backhandle, TS_EOF);
ssh_scp_recv(&ch, 1);
}
WSACleanup();

4096
ssh.c

Разница между файлами не показана из-за своего большого размера Загрузить разницу

9
ssh.h
Просмотреть файл

@ -227,7 +227,7 @@ extern char sshver[];
* that fails. This variable is the means by which scp.c can reach
* into the SSH code and find out which one it got.
*/
extern int ssh_fallback_cmd;
extern int ssh_fallback_cmd(void *handle);
#ifndef MSCRYPTOAPI
void SHATransform(word32 * digest, word32 * data);
@ -238,8 +238,11 @@ void random_add_noise(void *noise, int length);
void random_add_heavynoise(void *noise, int length);
void logevent(char *);
void *new_sock_channel(Socket s); // allocates and register a new channel for port forwarding
void ssh_send_port_open(void *channel, char *hostname, int port, char *org);
/* Allocate and register a new channel for port forwarding */
void *new_sock_channel(void *handle, Socket s);
void ssh_send_port_open(void *handle, void *channel,
char *hostname, int port, char *org);
Bignum copybn(Bignum b);
Bignum bn_power_2(int n);

481
telnet.c
Просмотреть файл

@ -11,11 +11,6 @@
#define TRUE 1
#endif
static Socket s = NULL;
static void *frontend;
static int telnet_term_width, telnet_term_height;
#define IAC 255 /* interpret as command: */
#define DONT 254 /* you are not to use option */
#define DO 253 /* please, you use option */
@ -141,59 +136,91 @@ static char *telopt(int opt)
return "<unknown>";
}
static void telnet_size(int width, int height);
static void telnet_size(void *handle, int width, int height);
struct Opt {
int send; /* what we initially send */
int nsend; /* -ve send if requested to stop it */
int ack, nak; /* +ve and -ve acknowledgements */
int option; /* the option code */
int index; /* index into telnet->opt_states[] */
enum {
REQUESTED, ACTIVE, INACTIVE, REALLY_INACTIVE
} state;
} initial_state;
};
static struct Opt o_naws =
{ WILL, WONT, DO, DONT, TELOPT_NAWS, REQUESTED };
static struct Opt o_tspeed =
{ WILL, WONT, DO, DONT, TELOPT_TSPEED, REQUESTED };
static struct Opt o_ttype =
{ WILL, WONT, DO, DONT, TELOPT_TTYPE, REQUESTED };
static struct Opt o_oenv = { WILL, WONT, DO, DONT, TELOPT_OLD_ENVIRON,
INACTIVE
enum {
OPTINDEX_NAWS,
OPTINDEX_TSPEED,
OPTINDEX_TTYPE,
OPTINDEX_OENV,
OPTINDEX_NENV,
OPTINDEX_ECHO,
OPTINDEX_WE_SGA,
OPTINDEX_THEY_SGA,
NUM_OPTS
};
static struct Opt o_nenv = { WILL, WONT, DO, DONT, TELOPT_NEW_ENVIRON,
REQUESTED
};
static struct Opt o_echo =
{ DO, DONT, WILL, WONT, TELOPT_ECHO, REQUESTED };
static struct Opt o_we_sga =
{ WILL, WONT, DO, DONT, TELOPT_SGA, REQUESTED };
static struct Opt o_they_sga =
{ DO, DONT, WILL, WONT, TELOPT_SGA, REQUESTED };
static struct Opt *opts[] = {
static const struct Opt o_naws =
{ WILL, WONT, DO, DONT, TELOPT_NAWS, OPTINDEX_NAWS, REQUESTED };
static const struct Opt o_tspeed =
{ WILL, WONT, DO, DONT, TELOPT_TSPEED, OPTINDEX_TSPEED, REQUESTED };
static const struct Opt o_ttype =
{ WILL, WONT, DO, DONT, TELOPT_TTYPE, OPTINDEX_TTYPE, REQUESTED };
static const struct Opt o_oenv = { WILL, WONT, DO, DONT, TELOPT_OLD_ENVIRON,
OPTINDEX_OENV, INACTIVE
};
static const struct Opt o_nenv = { WILL, WONT, DO, DONT, TELOPT_NEW_ENVIRON,
OPTINDEX_NENV, REQUESTED
};
static const struct Opt o_echo =
{ DO, DONT, WILL, WONT, TELOPT_ECHO, OPTINDEX_ECHO, REQUESTED };
static const struct Opt o_we_sga =
{ WILL, WONT, DO, DONT, TELOPT_SGA, OPTINDEX_WE_SGA, REQUESTED };
static const struct Opt o_they_sga =
{ DO, DONT, WILL, WONT, TELOPT_SGA, OPTINDEX_THEY_SGA, REQUESTED };
static const struct Opt *const opts[] = {
&o_naws, &o_tspeed, &o_ttype, &o_oenv, &o_nenv, &o_echo,
&o_we_sga, &o_they_sga, NULL
};
typedef struct telnet_tag {
const struct plug_function_table *fn;
/* the above field _must_ be first in the structure */
Socket s;
void *frontend;
int term_width, term_height;
int opt_states[NUM_OPTS];
int echoing, editing;
int activated;
int bufsize;
int in_synch;
int sb_opt, sb_len;
char *sb_buf;
int sb_size;
enum {
TOP_LEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT,
SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR
} state;
} *Telnet;
#define TELNET_MAX_BACKLOG 4096
static int echoing = TRUE, editing = TRUE;
static int activated = FALSE;
static int telnet_bufsize;
static int in_synch;
static int sb_opt, sb_len;
static char *sb_buf = NULL;
static int sb_size = 0;
#define SB_DELTA 1024
static void c_write1(int c)
static void c_write1(Telnet telnet, int c)
{
int backlog;
char cc = (char) c;
backlog = from_backend(frontend, 0, &cc, 1);
sk_set_frozen(s, backlog > TELNET_MAX_BACKLOG);
backlog = from_backend(telnet->frontend, 0, &cc, 1);
sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG);
}
static void log_option(char *sender, int cmd, int option)
@ -206,57 +233,58 @@ static void log_option(char *sender, int cmd, int option)
logevent(buf);
}
static void send_opt(int cmd, int option)
static void send_opt(Telnet telnet, int cmd, int option)
{
unsigned char b[3];
b[0] = IAC;
b[1] = cmd;
b[2] = option;
telnet_bufsize = sk_write(s, b, 3);
telnet->bufsize = sk_write(telnet->s, b, 3);
log_option("client", cmd, option);
}
static void deactivate_option(struct Opt *o)
static void deactivate_option(Telnet telnet, const struct Opt *o)
{
if (o->state == REQUESTED || o->state == ACTIVE)
send_opt(o->nsend, o->option);
o->state = REALLY_INACTIVE;
if (telnet->opt_states[o->index] == REQUESTED ||
telnet->opt_states[o->index] == ACTIVE)
send_opt(telnet, o->nsend, o->option);
telnet->opt_states[o->index] = REALLY_INACTIVE;
}
/*
* Generate side effects of enabling or disabling an option.
*/
static void option_side_effects(struct Opt *o, int enabled)
static void option_side_effects(Telnet telnet, const struct Opt *o, int enabled)
{
if (o->option == TELOPT_ECHO && o->send == DO)
echoing = !enabled;
telnet->echoing = !enabled;
else if (o->option == TELOPT_SGA && o->send == DO)
editing = !enabled;
telnet->editing = !enabled;
ldisc_send(NULL, 0, 0); /* cause ldisc to notice the change */
/* Ensure we get the minimum options */
if (!activated) {
if (o_echo.state == INACTIVE) {
o_echo.state = REQUESTED;
send_opt(o_echo.send, o_echo.option);
if (!telnet->activated) {
if (telnet->opt_states[o_echo.index] == INACTIVE) {
telnet->opt_states[o_echo.index] = REQUESTED;
send_opt(telnet, o_echo.send, o_echo.option);
}
if (o_we_sga.state == INACTIVE) {
o_we_sga.state = REQUESTED;
send_opt(o_we_sga.send, o_we_sga.option);
if (telnet->opt_states[o_we_sga.index] == INACTIVE) {
telnet->opt_states[o_we_sga.index] = REQUESTED;
send_opt(telnet, o_we_sga.send, o_we_sga.option);
}
if (o_they_sga.state == INACTIVE) {
o_they_sga.state = REQUESTED;
send_opt(o_they_sga.send, o_they_sga.option);
if (telnet->opt_states[o_they_sga.index] == INACTIVE) {
telnet->opt_states[o_they_sga.index] = REQUESTED;
send_opt(telnet, o_they_sga.send, o_they_sga.option);
}
activated = TRUE;
telnet->activated = TRUE;
}
}
static void activate_option(struct Opt *o)
static void activate_option(Telnet telnet, const struct Opt *o)
{
if (o->send == WILL && o->option == TELOPT_NAWS)
telnet_size(telnet_term_width, telnet_term_height);
telnet_size(telnet, telnet->term_width, telnet->term_height);
if (o->send == WILL &&
(o->option == TELOPT_NEW_ENVIRON ||
o->option == TELOPT_OLD_ENVIRON)) {
@ -264,56 +292,56 @@ static void activate_option(struct Opt *o)
* We may only have one kind of ENVIRON going at a time.
* This is a hack, but who cares.
*/
deactivate_option(o->option ==
deactivate_option(telnet, o->option ==
TELOPT_NEW_ENVIRON ? &o_oenv : &o_nenv);
}
option_side_effects(o, 1);
option_side_effects(telnet, o, 1);
}
static void refused_option(struct Opt *o)
static void refused_option(Telnet telnet, const struct Opt *o)
{
if (o->send == WILL && o->option == TELOPT_NEW_ENVIRON &&
o_oenv.state == INACTIVE) {
send_opt(WILL, TELOPT_OLD_ENVIRON);
o_oenv.state = REQUESTED;
telnet->opt_states[o_oenv.index] == INACTIVE) {
send_opt(telnet, WILL, TELOPT_OLD_ENVIRON);
telnet->opt_states[o_oenv.index] = REQUESTED;
}
option_side_effects(o, 0);
option_side_effects(telnet, o, 0);
}
static void proc_rec_opt(int cmd, int option)
static void proc_rec_opt(Telnet telnet, int cmd, int option)
{
struct Opt **o;
const struct Opt *const *o;
log_option("server", cmd, option);
for (o = opts; *o; o++) {
if ((*o)->option == option && (*o)->ack == cmd) {
switch ((*o)->state) {
switch (telnet->opt_states[(*o)->index]) {
case REQUESTED:
(*o)->state = ACTIVE;
activate_option(*o);
telnet->opt_states[(*o)->index] = ACTIVE;
activate_option(telnet, *o);
break;
case ACTIVE:
break;
case INACTIVE:
(*o)->state = ACTIVE;
send_opt((*o)->send, option);
activate_option(*o);
telnet->opt_states[(*o)->index] = ACTIVE;
send_opt(telnet, (*o)->send, option);
activate_option(telnet, *o);
break;
case REALLY_INACTIVE:
send_opt((*o)->nsend, option);
send_opt(telnet, (*o)->nsend, option);
break;
}
return;
} else if ((*o)->option == option && (*o)->nak == cmd) {
switch ((*o)->state) {
switch (telnet->opt_states[(*o)->index]) {
case REQUESTED:
(*o)->state = INACTIVE;
refused_option(*o);
telnet->opt_states[(*o)->index] = INACTIVE;
refused_option(telnet, *o);
break;
case ACTIVE:
(*o)->state = INACTIVE;
send_opt((*o)->nsend, option);
option_side_effects(*o, 0);
telnet->opt_states[(*o)->index] = INACTIVE;
send_opt(telnet, (*o)->nsend, option);
option_side_effects(telnet, *o, 0);
break;
case INACTIVE:
case REALLY_INACTIVE:
@ -326,18 +354,18 @@ static void proc_rec_opt(int cmd, int option)
* If we reach here, the option was one we weren't prepared to
* cope with. So send a negative ack.
*/
send_opt((cmd == WILL ? DONT : WONT), option);
send_opt(telnet, (cmd == WILL ? DONT : WONT), option);
}
static void process_subneg(void)
static void process_subneg(Telnet telnet)
{
unsigned char b[2048], *p, *q;
int var, value, n;
char *e;
switch (sb_opt) {
switch (telnet->sb_opt) {
case TELOPT_TSPEED:
if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) {
if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) {
char logbuf[sizeof(cfg.termspeed) + 80];
b[0] = IAC;
b[1] = SB;
@ -347,7 +375,7 @@ static void process_subneg(void)
n = 4 + strlen(cfg.termspeed);
b[n] = IAC;
b[n + 1] = SE;
telnet_bufsize = sk_write(s, b, n + 2);
telnet->bufsize = sk_write(telnet->s, b, n + 2);
logevent("server:\tSB TSPEED SEND");
sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed);
logevent(logbuf);
@ -355,7 +383,7 @@ static void process_subneg(void)
logevent("server:\tSB TSPEED <something weird>");
break;
case TELOPT_TTYPE:
if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) {
if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) {
char logbuf[sizeof(cfg.termtype) + 80];
b[0] = IAC;
b[1] = SB;
@ -368,7 +396,7 @@ static void process_subneg(void)
'a' : cfg.termtype[n]);
b[n + 4] = IAC;
b[n + 5] = SE;
telnet_bufsize = sk_write(s, b, n + 6);
telnet->bufsize = sk_write(telnet->s, b, n + 6);
b[n + 4] = 0;
logevent("server:\tSB TTYPE SEND");
sprintf(logbuf, "client:\tSB TTYPE IS %s", b + 4);
@ -378,14 +406,14 @@ static void process_subneg(void)
break;
case TELOPT_OLD_ENVIRON:
case TELOPT_NEW_ENVIRON:
p = sb_buf;
q = p + sb_len;
p = telnet->sb_buf;
q = p + telnet->sb_len;
if (p < q && *p == TELQUAL_SEND) {
char logbuf[50];
p++;
sprintf(logbuf, "server:\tSB %s SEND", telopt(sb_opt));
sprintf(logbuf, "server:\tSB %s SEND", telopt(telnet->sb_opt));
logevent(logbuf);
if (sb_opt == TELOPT_OLD_ENVIRON) {
if (telnet->sb_opt == TELOPT_OLD_ENVIRON) {
if (cfg.rfc_environ) {
value = RFC_VALUE;
var = RFC_VAR;
@ -416,7 +444,7 @@ static void process_subneg(void)
}
b[0] = IAC;
b[1] = SB;
b[2] = sb_opt;
b[2] = telnet->sb_opt;
b[3] = TELQUAL_IS;
n = 4;
e = cfg.environmt;
@ -444,8 +472,8 @@ static void process_subneg(void)
}
b[n++] = IAC;
b[n++] = SE;
telnet_bufsize = sk_write(s, b, n);
sprintf(logbuf, "client:\tSB %s IS %s", telopt(sb_opt),
telnet->bufsize = sk_write(telnet->s, b, n);
sprintf(logbuf, "client:\tSB %s IS %s", telopt(telnet->sb_opt),
n == 6 ? "<nothing>" : "<stuff>");
logevent(logbuf);
}
@ -453,27 +481,22 @@ static void process_subneg(void)
}
}
static enum {
TOP_LEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT,
SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR
} telnet_state = TOP_LEVEL;
static void do_telnet_read(char *buf, int len)
static void do_telnet_read(Telnet telnet, char *buf, int len)
{
while (len--) {
int c = (unsigned char) *buf++;
switch (telnet_state) {
switch (telnet->state) {
case TOP_LEVEL:
case SEENCR:
if (c == NUL && telnet_state == SEENCR)
telnet_state = TOP_LEVEL;
if (c == NUL && telnet->state == SEENCR)
telnet->state = TOP_LEVEL;
else if (c == IAC)
telnet_state = SEENIAC;
telnet->state = SEENIAC;
else {
if (!in_synch)
c_write1(c);
if (!telnet->in_synch)
c_write1(telnet, c);
#if 1
/* I can't get the F***ing winsock to insert the urgent IAC
@ -485,84 +508,84 @@ static void do_telnet_read(char *buf, int len)
* just stop hiding on the next 0xf2 and hope for the best.
*/
else if (c == DM)
in_synch = 0;
telnet->in_synch = 0;
#endif
if (c == CR)
telnet_state = SEENCR;
telnet->state = SEENCR;
else
telnet_state = TOP_LEVEL;
telnet->state = TOP_LEVEL;
}
break;
case SEENIAC:
if (c == DO)
telnet_state = SEENDO;
telnet->state = SEENDO;
else if (c == DONT)
telnet_state = SEENDONT;
telnet->state = SEENDONT;
else if (c == WILL)
telnet_state = SEENWILL;
telnet->state = SEENWILL;
else if (c == WONT)
telnet_state = SEENWONT;
telnet->state = SEENWONT;
else if (c == SB)
telnet_state = SEENSB;
telnet->state = SEENSB;
else if (c == DM) {
in_synch = 0;
telnet_state = TOP_LEVEL;
telnet->in_synch = 0;
telnet->state = TOP_LEVEL;
} else {
/* ignore everything else; print it if it's IAC */
if (c == IAC) {
c_write1(c);
c_write1(telnet, c);
}
telnet_state = TOP_LEVEL;
telnet->state = TOP_LEVEL;
}
break;
case SEENWILL:
proc_rec_opt(WILL, c);
telnet_state = TOP_LEVEL;
proc_rec_opt(telnet, WILL, c);
telnet->state = TOP_LEVEL;
break;
case SEENWONT:
proc_rec_opt(WONT, c);
telnet_state = TOP_LEVEL;
proc_rec_opt(telnet, WONT, c);
telnet->state = TOP_LEVEL;
break;
case SEENDO:
proc_rec_opt(DO, c);
telnet_state = TOP_LEVEL;
proc_rec_opt(telnet, DO, c);
telnet->state = TOP_LEVEL;
break;
case SEENDONT:
proc_rec_opt(DONT, c);
telnet_state = TOP_LEVEL;
proc_rec_opt(telnet, DONT, c);
telnet->state = TOP_LEVEL;
break;
case SEENSB:
sb_opt = c;
sb_len = 0;
telnet_state = SUBNEGOT;
telnet->sb_opt = c;
telnet->sb_len = 0;
telnet->state = SUBNEGOT;
break;
case SUBNEGOT:
if (c == IAC)
telnet_state = SUBNEG_IAC;
telnet->state = SUBNEG_IAC;
else {
subneg_addchar:
if (sb_len >= sb_size) {
if (telnet->sb_len >= telnet->sb_size) {
char *newbuf;
sb_size += SB_DELTA;
newbuf = (sb_buf ?
srealloc(sb_buf, sb_size) :
smalloc(sb_size));
telnet->sb_size += SB_DELTA;
newbuf = (telnet->sb_buf ?
srealloc(telnet->sb_buf, telnet->sb_size) :
smalloc(telnet->sb_size));
if (newbuf)
sb_buf = newbuf;
telnet->sb_buf = newbuf;
else
sb_size -= SB_DELTA;
telnet->sb_size -= SB_DELTA;
}
if (sb_len < sb_size)
sb_buf[sb_len++] = c;
telnet_state = SUBNEGOT; /* in case we came here by goto */
if (telnet->sb_len < telnet->sb_size)
telnet->sb_buf[telnet->sb_len++] = c;
telnet->state = SUBNEGOT; /* in case we came here by goto */
}
break;
case SUBNEG_IAC:
if (c != SE)
goto subneg_addchar; /* yes, it's a hack, I know, but... */
else {
process_subneg();
telnet_state = TOP_LEVEL;
process_subneg(telnet);
telnet->state = TOP_LEVEL;
}
break;
}
@ -572,9 +595,11 @@ static void do_telnet_read(char *buf, int len)
static int telnet_closing(Plug plug, char *error_msg, int error_code,
int calling_back)
{
if (s) {
sk_close(s);
s = NULL;
Telnet telnet = (Telnet) plug;
if (telnet->s) {
sk_close(telnet->s);
telnet->s = NULL;
}
if (error_msg) {
/* A socket error has occurred. */
@ -586,15 +611,17 @@ static int telnet_closing(Plug plug, char *error_msg, int error_code,
static int telnet_receive(Plug plug, int urgent, char *data, int len)
{
Telnet telnet = (Telnet) plug;
if (urgent)
in_synch = TRUE;
do_telnet_read(data, len);
telnet->in_synch = TRUE;
do_telnet_read(telnet, data, len);
return 1;
}
static void telnet_sent(Plug plug, int bufsize)
{
telnet_bufsize = bufsize;
Telnet telnet = (Telnet) plug;
telnet->bufsize = bufsize;
}
/*
@ -605,21 +632,31 @@ static void telnet_sent(Plug plug, int bufsize)
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
static char *telnet_init(void *frontend_handle,
static char *telnet_init(void *frontend_handle, void **backend_handle,
char *host, int port, char **realhost, int nodelay)
{
static struct plug_function_table fn_table = {
static const struct plug_function_table fn_table = {
telnet_closing,
telnet_receive,
telnet_sent
}, *fn_table_ptr = &fn_table;
};
SockAddr addr;
char *err;
Telnet telnet;
frontend = frontend_handle;
telnet_term_width = cfg.width;
telnet_term_height = cfg.height;
telnet = smalloc(sizeof(*telnet));
telnet->fn = &fn_table;
telnet->s = NULL;
telnet->echoing = TRUE;
telnet->editing = TRUE;
telnet->activated = FALSE;
telnet->sb_buf = NULL;
telnet->sb_size = 0;
telnet->frontend = frontend_handle;
telnet->term_width = cfg.width;
telnet->term_height = cfg.height;
telnet->state = TOP_LEVEL;
*backend_handle = telnet;
/*
* Try to find host.
@ -645,8 +682,9 @@ static char *telnet_init(void *frontend_handle,
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
logevent(buf);
}
s = new_connection(addr, *realhost, port, 0, 1, nodelay, &fn_table_ptr);
if ((err = sk_socket_error(s)))
telnet->s = new_connection(addr, *realhost, port, 0, 1,
nodelay, (Plug) telnet);
if ((err = sk_socket_error(telnet->s)))
return err;
sk_addr_free(addr);
@ -655,24 +693,25 @@ static char *telnet_init(void *frontend_handle,
* Initialise option states.
*/
if (cfg.passive_telnet) {
struct Opt **o;
const struct Opt *const *o;
for (o = opts; *o; o++)
if ((*o)->state == REQUESTED)
(*o)->state = INACTIVE;
telnet->opt_states[(*o)->index] = INACTIVE;
} else {
struct Opt **o;
const struct Opt *const *o;
for (o = opts; *o; o++)
if ((*o)->state == REQUESTED)
send_opt((*o)->send, (*o)->option);
activated = TRUE;
for (o = opts; *o; o++) {
telnet->opt_states[(*o)->index] = (*o)->initial_state;
if (telnet->opt_states[(*o)->index] == REQUESTED)
send_opt(telnet, (*o)->send, (*o)->option);
}
telnet->activated = TRUE;
}
/*
* Set up SYNCH state.
*/
in_synch = FALSE;
telnet->in_synch = FALSE;
return NULL;
}
@ -680,8 +719,9 @@ static char *telnet_init(void *frontend_handle,
/*
* Called to send data down the Telnet connection.
*/
static int telnet_send(char *buf, int len)
static int telnet_send(void *handle, char *buf, int len)
{
Telnet telnet = (Telnet) handle;
char *p;
static unsigned char iac[2] = { IAC, IAC };
static unsigned char cr[2] = { CR, NUL };
@ -689,7 +729,7 @@ static int telnet_send(char *buf, int len)
static unsigned char nl[2] = { CR, LF };
#endif
if (s == NULL)
if (telnet->s == NULL)
return 0;
p = buf;
@ -698,49 +738,51 @@ static int telnet_send(char *buf, int len)
while (iswritable((unsigned char) *p) && p < buf + len)
p++;
telnet_bufsize = sk_write(s, q, p - q);
telnet->bufsize = sk_write(telnet->s, q, p - q);
while (p < buf + len && !iswritable((unsigned char) *p)) {
telnet_bufsize =
sk_write(s, (unsigned char) *p == IAC ? iac : cr, 2);
telnet->bufsize =
sk_write(telnet->s, (unsigned char) *p == IAC ? iac : cr, 2);
p++;
}
}
return telnet_bufsize;
return telnet->bufsize;
}
/*
* Called to query the current socket sendability status.
*/
static int telnet_sendbuffer(void)
static int telnet_sendbuffer(void *handle)
{
return telnet_bufsize;
Telnet telnet = (Telnet) handle;
return telnet->bufsize;
}
/*
* Called to set the size of the window from Telnet's POV.
*/
static void telnet_size(int width, int height)
static void telnet_size(void *handle, int width, int height)
{
Telnet telnet = (Telnet) handle;
unsigned char b[16];
char logbuf[50];
telnet_term_width = width;
telnet_term_height = height;
telnet->term_width = width;
telnet->term_height = height;
if (s == NULL || o_naws.state != ACTIVE)
if (telnet->s == NULL || telnet->opt_states[o_naws.index] != ACTIVE)
return;
b[0] = IAC;
b[1] = SB;
b[2] = TELOPT_NAWS;
b[3] = telnet_term_width >> 8;
b[4] = telnet_term_width & 0xFF;
b[5] = telnet_term_height >> 8;
b[6] = telnet_term_height & 0xFF;
b[3] = telnet->term_width >> 8;
b[4] = telnet->term_width & 0xFF;
b[5] = telnet->term_height >> 8;
b[6] = telnet->term_height & 0xFF;
b[7] = IAC;
b[8] = SE;
telnet_bufsize = sk_write(s, b, 9);
telnet->bufsize = sk_write(telnet->s, b, 9);
sprintf(logbuf, "client:\tSB NAWS %d,%d",
((unsigned char) b[3] << 8) + (unsigned char) b[4],
((unsigned char) b[5] << 8) + (unsigned char) b[6]);
@ -750,118 +792,125 @@ static void telnet_size(int width, int height)
/*
* Send Telnet special codes.
*/
static void telnet_special(Telnet_Special code)
static void telnet_special(void *handle, Telnet_Special code)
{
Telnet telnet = (Telnet) handle;
unsigned char b[2];
if (s == NULL)
if (telnet->s == NULL)
return;
b[0] = IAC;
switch (code) {
case TS_AYT:
b[1] = AYT;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_BRK:
b[1] = BREAK;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EC:
b[1] = EC;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EL:
b[1] = EL;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_GA:
b[1] = GA;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_NOP:
b[1] = NOP;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_ABORT:
b[1] = ABORT;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_AO:
b[1] = AO;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_IP:
b[1] = IP;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_SUSP:
b[1] = SUSP;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EOR:
b[1] = EOR;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EOF:
b[1] = xEOF;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
break;
case TS_EOL:
telnet_bufsize = sk_write(s, "\r\n", 2);
telnet->bufsize = sk_write(telnet->s, "\r\n", 2);
break;
case TS_SYNCH:
b[1] = DM;
telnet_bufsize = sk_write(s, b, 1);
telnet_bufsize = sk_write_oob(s, b + 1, 1);
telnet->bufsize = sk_write(telnet->s, b, 1);
telnet->bufsize = sk_write_oob(telnet->s, b + 1, 1);
break;
case TS_RECHO:
if (o_echo.state == INACTIVE || o_echo.state == REALLY_INACTIVE) {
o_echo.state = REQUESTED;
send_opt(o_echo.send, o_echo.option);
if (telnet->opt_states[o_echo.index] == INACTIVE ||
telnet->opt_states[o_echo.index] == REALLY_INACTIVE) {
telnet->opt_states[o_echo.index] = REQUESTED;
send_opt(telnet, o_echo.send, o_echo.option);
}
break;
case TS_LECHO:
if (o_echo.state == ACTIVE) {
o_echo.state = REQUESTED;
send_opt(o_echo.nsend, o_echo.option);
if (telnet->opt_states[o_echo.index] == ACTIVE) {
telnet->opt_states[o_echo.index] = REQUESTED;
send_opt(telnet, o_echo.nsend, o_echo.option);
}
break;
case TS_PING:
if (o_they_sga.state == ACTIVE) {
if (telnet->opt_states[o_they_sga.index] == ACTIVE) {
b[1] = NOP;
telnet_bufsize = sk_write(s, b, 2);
telnet->bufsize = sk_write(telnet->s, b, 2);
}
break;
}
}
static Socket telnet_socket(void)
static Socket telnet_socket(void *handle)
{
return s;
Telnet telnet = (Telnet) handle;
return telnet->s;
}
static int telnet_sendok(void)
static int telnet_sendok(void *handle)
{
Telnet telnet = (Telnet) handle;
return 1;
}
static void telnet_unthrottle(int backlog)
static void telnet_unthrottle(void *handle, int backlog)
{
sk_set_frozen(s, backlog > TELNET_MAX_BACKLOG);
Telnet telnet = (Telnet) handle;
sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG);
}
static int telnet_ldisc(int option)
static int telnet_ldisc(void *handle, int option)
{
Telnet telnet = (Telnet) handle;
if (option == LD_ECHO)
return echoing;
return telnet->echoing;
if (option == LD_EDIT)
return editing;
return telnet->editing;
return FALSE;
}
static int telnet_exitcode(void)
static int telnet_exitcode(void *handle)
{
Telnet telnet = (Telnet) handle;
/* Telnet doesn't transmit exit codes back to the client */
return 0;
}

Просмотреть файл

@ -328,6 +328,8 @@ Terminal *term_init(void)
term->nbeeps = 0;
term->lastbeep = FALSE;
term->beep_overloaded = FALSE;
term->resize_fn = NULL;
term->resize_ctx = NULL;
return term;
}
@ -455,7 +457,22 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
update_sbar(term);
term_update(term);
back->size(term->cols, term->rows);
if (term->resize_fn)
term->resize_fn(term->resize_ctx, term->cols, term->rows);
}
/*
* Hand a function and context pointer to the terminal which it can
* use to notify a back end of resizes.
*/
void term_provide_resize_fn(Terminal *term,
void (*resize_fn)(void *, int, int),
void *resize_ctx)
{
term->resize_fn = resize_fn;
term->resize_ctx = resize_ctx;
if (term->cols > 0 && term->rows > 0)
resize_fn(resize_ctx, term->cols, term->rows);
}
/*

Просмотреть файл

@ -157,6 +157,9 @@ struct terminal_tag {
wchar_t *paste_buffer;
int paste_len, paste_pos, paste_hold;
long last_paste;
void (*resize_fn)(void *, int, int);
void *resize_ctx;
};
#define in_utf(term) ((term)->utf || line_codepage==CP_UTF8)

Просмотреть файл

@ -600,7 +600,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
char msg[1024], *title;
char *realhost;
error = back->init((void *)term,
error = back->init((void *)term, &backhandle,
cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
if (error) {
sprintf(msg, "Unable to open connection to\n"
@ -620,6 +620,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
set_icon(title);
}
/*
* Connect the terminal to the backend for resize purposes.
*/
term_provide_resize_fn(term, back->size, backhandle);
session_closed = FALSE;
/*
@ -1610,7 +1615,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
time_t now;
time(&now);
if (now - last_movement > cfg.ping_interval) {
back->special(TS_PING);
back->special(backhandle, TS_PING);
last_movement = now;
}
}
@ -1860,55 +1865,55 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
ldisc_send(NULL, 0, 0);
break;
case IDM_TEL_AYT:
back->special(TS_AYT);
back->special(backhandle, TS_AYT);
net_pending_errors();
break;
case IDM_TEL_BRK:
back->special(TS_BRK);
back->special(backhandle, TS_BRK);
net_pending_errors();
break;
case IDM_TEL_SYNCH:
back->special(TS_SYNCH);
back->special(backhandle, TS_SYNCH);
net_pending_errors();
break;
case IDM_TEL_EC:
back->special(TS_EC);
back->special(backhandle, TS_EC);
net_pending_errors();
break;
case IDM_TEL_EL:
back->special(TS_EL);
back->special(backhandle, TS_EL);
net_pending_errors();
break;
case IDM_TEL_GA:
back->special(TS_GA);
back->special(backhandle, TS_GA);
net_pending_errors();
break;
case IDM_TEL_NOP:
back->special(TS_NOP);
back->special(backhandle, TS_NOP);
net_pending_errors();
break;
case IDM_TEL_ABORT:
back->special(TS_ABORT);
back->special(backhandle, TS_ABORT);
net_pending_errors();
break;
case IDM_TEL_AO:
back->special(TS_AO);
back->special(backhandle, TS_AO);
net_pending_errors();
break;
case IDM_TEL_IP:
back->special(TS_IP);
back->special(backhandle, TS_IP);
net_pending_errors();
break;
case IDM_TEL_SUSP:
back->special(TS_SUSP);
back->special(backhandle, TS_SUSP);
net_pending_errors();
break;
case IDM_TEL_EOR:
back->special(TS_EOR);
back->special(backhandle, TS_EOR);
net_pending_errors();
break;
case IDM_TEL_EOF:
back->special(TS_EOF);
back->special(backhandle, TS_EOF);
net_pending_errors();
break;
case IDM_ABOUT: