1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-27 02:02:26 +00:00

Lots of MacTCP networking stuff. I think all the code's written, but it

doesn't actually work yet.  Also the telnet backend is still single-session,
and I haven't even touched the ssh one.  Oh, and the "Main" segment just
overflowed 32k, so we have extra linker incantations.  I'm off to the pub
now.

[originally from svn r156]
This commit is contained in:
Ben Harris 1999-04-04 18:23:35 +00:00
parent efc9e4260c
commit 0256bceece
8 changed files with 234 additions and 206 deletions

View File

@ -1,4 +1,4 @@
# $Id: Makefile.mpw,v 1.1.2.11 1999/04/03 21:53:29 ben Exp $ # $Id: Makefile.mpw,v 1.1.2.12 1999/04/04 18:23:33 ben Exp $
# This is the Makefile for building PuTTY for the Mac OS. # This is the Makefile for building PuTTY for the Mac OS.
# Users of non-Mac systems will see some pretty strange characters around. # Users of non-Mac systems will see some pretty strange characters around.
@ -13,8 +13,10 @@ COptions = {Includes} {Sym
PPCCOptions = {Includes} {Sym¥PPC} -w 35 PPCCOptions = {Includes} {Sym¥PPC} -w 35
Objects¥68K = Objects¥68K =
dnr.c.o ¶
mac.c.o ¶ mac.c.o ¶
maccfg.c.o ¶ maccfg.c.o ¶
macnet.c.o ¶
macterm.c.o ¶ macterm.c.o ¶
misc.c.o ¶ misc.c.o ¶
# ssh.c.o ¶ # ssh.c.o ¶
@ -24,13 +26,15 @@ Objects
# sshrand.c.o ¶ # sshrand.c.o ¶
# sshrsa.c.o ¶ # sshrsa.c.o ¶
# sshsha.c.o ¶ # sshsha.c.o ¶
# telnet.c.o ¶ telnet.c.o ¶
terminal.c.o ¶ terminal.c.o ¶
testback.c.o testback.c.o
Objects¥PPC = Objects¥PPC =
dnr.c.x ¶
mac.c.x ¶ mac.c.x ¶
maccfg.c.x ¶ maccfg.c.x ¶
macnet.c.x ¶
macterm.c.x ¶ macterm.c.x ¶
misc.c.x ¶ misc.c.x ¶
# ssh.c.x ¶ # ssh.c.x ¶
@ -40,7 +44,7 @@ Objects
# sshrand.c.x ¶ # sshrand.c.x ¶
# sshrsa.c.x ¶ # sshrsa.c.x ¶
# sshsha.c.x ¶ # sshsha.c.x ¶
# telnet.c.x ¶ telnet.c.x ¶
terminal.c.x ¶ terminal.c.x ¶
testback.c.x testback.c.x
@ -89,11 +93,13 @@ PuTTY.68k
ILink ¶ ILink ¶
-o {Targ} {Sym¥68K} -o {Targ} {Sym¥68K}
-t 'APPL' -c 'pTTY' -t 'APPL' -c 'pTTY'
-br 68k -model far ¶
-newerdeps {NewerDeps} -newerdeps {NewerDeps}
ELSE ELSE
ILink ¶ ILink ¶
-o {Targ} {Sym¥68K} -o {Targ} {Sym¥68K}
-t 'APPL' -c 'pTTY' -t 'APPL' -c 'pTTY'
-br 68k -model far¶
{Objects¥68K} {Objects¥68K}
{Libs¥68K} {Libs¥68K}
END END
@ -118,6 +124,7 @@ PuTTY
setfile -t XCOF {Targ} setfile -t XCOF {Targ}
{PPCC} {default}.c -o {Targ} {PPCCOptions} {PPCC} {default}.c -o {Targ} {PPCCOptions}
dnr.c.o dnr.c.x Ä
mac.c.o mac.c.x Ä putty.h mac.h macresid.h mac.c.o mac.c.x Ä putty.h mac.h macresid.h
maccfg.c.o maccfg.c.x Ä putty.h mac.h macresid.h maccfg.c.o maccfg.c.x Ä putty.h mac.h macresid.h
macnet.c.o macnet.c.x Ä putty.h macnet.c.o macnet.c.x Ä putty.h

3
mac.c
View File

@ -1,4 +1,4 @@
/* $Id: mac.c,v 1.1.2.23 1999/04/02 12:58:02 ben Exp $ */ /* $Id: mac.c,v 1.1.2.24 1999/04/04 18:23:33 ben Exp $ */
/* /*
* Copyright (c) 1999 Ben Harris * Copyright (c) 1999 Ben Harris
* All rights reserved. * All rights reserved.
@ -159,6 +159,7 @@ static void mac_eventloop(void) {
mac_adjustcursor(cursrgn); mac_adjustcursor(cursrgn);
if (gotevent) if (gotevent)
mac_event(&event); mac_event(&event);
macnet_eventcheck();
} }
DisposeRgn(cursrgn); DisposeRgn(cursrgn);
} }

2
mac.h
View File

@ -30,6 +30,8 @@ extern void mac_keyterm(WindowPtr, EventRecord *);
extern void mac_menuterm(WindowPtr, short, short); extern void mac_menuterm(WindowPtr, short, short);
/* from maccfg.c */ /* from maccfg.c */
extern void mac_loadconfig(Config *); extern void mac_loadconfig(Config *);
/* from macnet.c */
extern void macnet_eventcheck(void);
#endif #endif

160
macnet.c
View File

@ -1,4 +1,4 @@
/* $Id: macnet.c,v 1.1.2.2 1999/04/03 21:53:29 ben Exp $ */ /* $Id: macnet.c,v 1.1.2.3 1999/04/04 18:23:34 ben Exp $ */
/* /*
* Copyright (c) 1999 Ben Harris * Copyright (c) 1999 Ben Harris
* All rights reserved. * All rights reserved.
@ -73,21 +73,17 @@ typedef struct Socket {
TCPiopb spareiopb; /* for closing etc */ TCPiopb spareiopb; /* for closing etc */
hostInfo hostinfo; hostInfo hostinfo;
int port; int port;
// unsigned char *inbuf;
// int inbuf_head, inbuf_reap, inbuf_size;
// unsigned char *outbuf;
// int outbuf_head, outbuf_reap, outbuf_size;
ProcessSerialNumber psn; ProcessSerialNumber psn;
Session *s; Session *s;
UInt32 a5; long a5;
qHdr sendq; /* Blocks waiting to be sent */ QHdr sendq; /* Blocks waiting to be sent */
qHdr freeq; /* Blocks sent, waiting to be freed */
} Socket; } Socket;
typedef struct { typedef struct {
QElem qelem; QElem qelem;
int flags; int flags;
int len; wdsEntry wds;
short wdsterm;
} Send_Buffer; } Send_Buffer;
/* /*
@ -112,9 +108,11 @@ static int mtcp_initted = FALSE;
static OSErr macnet_init(void); static OSErr macnet_init(void);
static pascal void macnet_resolved(hostInfo *, char *); static pascal void macnet_resolved(hostInfo *, char *);
static void macnet_opened(TCPiopb*); static void macnet_completed_open(TCPiopb*);
static void macnet_sent(TCPiopb*); static void macnet_completed_send(TCPiopb*);
static void macnet_closed(TCPiopb*); static void macnet_sent(Socket *);
static void macnet_startsend(Socket *);
static void macnet_completed_close(TCPiopb*);
static pascal void macnet_asr(StreamPtr, unsigned short, Ptr, unsigned short, static pascal void macnet_asr(StreamPtr, unsigned short, Ptr, unsigned short,
ICMPReport *); ICMPReport *);
static void macnet_sendevent(Socket *, Net_Event_Type); static void macnet_sendevent(Socket *, Net_Event_Type);
@ -122,21 +120,22 @@ static void macnet_sendevent(Socket *, Net_Event_Type);
#if TARGET_RT_MAC_CFM #if TARGET_RT_MAC_CFM
static RoutineDescriptor macnet_resolved_upp = static RoutineDescriptor macnet_resolved_upp =
BUILD_ROUTINE_DESCRIPTOR(uppResultProcInfo, (ProcPtr)macnet_resolved); BUILD_ROUTINE_DESCRIPTOR(uppResultProcInfo, (ProcPtr)macnet_resolved);
static RoutineDescriptor macnet_opened_upp = static RoutineDescriptor macnet_completed_open_upp =
BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo, BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo,
(ProcPtr)macnet_opened); (ProcPtr)macnet_completed_open);
static RoutineDescriptor macnet_sent_upp = static RoutineDescriptor macnet_complete_send_upp =
BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo, (ProcPtr)macnet_sent);
static RoutineDescriptor macnet_closed_upp =
BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo, BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo,
(ProcPtr)macnet_closed); (ProcPtr)macnet_completed_send);
static RoutineDescriptor macnet_completed_close_upp =
BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo,
(ProcPtr)macnet_completed_close);
static RoutineDescriptor macnet_asr_upp = static RoutineDescriptor macnet_asr_upp =
BUILD_ROUTINE_DESCRIPTOR(uppTCPNotifyProcInfo, (ProcPtr)macnet_asr); BUILD_ROUTINE_DESCRIPTOR(uppTCPNotifyProcInfo, (ProcPtr)macnet_asr);
#else #else
#define macnet_resolved_upp macnet_resolved #define macnet_resolved_upp macnet_resolved
#define macnet_opened_upp macnet_opened #define macnet_completed_open_upp macnet_completed_open
#define macnet_sent_upp macnet_sent #define macnet_completed_send_upp macnet_completed_send
#define macnet_closed_upp macnet_closed #define macnet_completed_close_upp macnet_completed_close
#define macnet_asr_upp macnet_asr #define macnet_asr_upp macnet_asr
#endif #endif
@ -153,13 +152,18 @@ static OSErr macnet_init(void) {
NetEvent *eventblock; NetEvent *eventblock;
int i; int i;
/*
* FIXME: This is hideously broken, in that we're meant to faff
* with unit numbers and stuff, and we blatantly don't.
*/
err = opendriver(".IPP", &mtcp_refnum); err = opendriver(".IPP", &mtcp_refnum);
if (err != noErr) if (err != noErr)
return err; return err;
err = OpenResolver(NULL); err = OpenResolver(NULL);
if (err != noErr) if (err != noErr)
return err; return err;
/* Set up the event queues, and fill the free queue with events */ /* Set up the event queues, and fill the free queue with events
*/
macnet_eventq.qFlags = 0; macnet_eventq.qFlags = 0;
macnet_eventq.qHead = macnet_eventq.qTail = NULL; macnet_eventq.qHead = macnet_eventq.qTail = NULL;
macnet_freeq.qFlags = 0; macnet_freeq.qFlags = 0;
@ -168,6 +172,7 @@ static OSErr macnet_init(void) {
for (i = 0; i < NUM_EVENTS; i++) for (i = 0; i < NUM_EVENTS; i++)
Enqueue(&eventblock[i].qelem, &macnet_freeq); Enqueue(&eventblock[i].qelem, &macnet_freeq);
mtcp_initted = TRUE; mtcp_initted = TRUE;
return 0;
} }
Socket *net_open(Session *s, char *host, int port) { Socket *net_open(Session *s, char *host, int port) {
@ -217,9 +222,11 @@ Socket *net_open(Session *s, char *host, int port) {
static pascal void macnet_resolved(hostInfo *hi, char *cookie) { static pascal void macnet_resolved(hostInfo *hi, char *cookie) {
Socket *sock = (Socket *)cookie; Socket *sock = (Socket *)cookie;
OSErr err; OSErr err;
UInt32 olda5; #if !TARGET_RT_CFM
long olda5;
olda5 = SetA5(sock->a5); olda5 = SetA5(sock->a5);
#endif
/* /*
* We've resolved a name, so now we'd like to connect to it (or * We've resolved a name, so now we'd like to connect to it (or
* report an error). * report an error).
@ -227,7 +234,7 @@ static pascal void macnet_resolved(hostInfo *hi, char *cookie) {
switch (sock->hostinfo.rtnCode) { switch (sock->hostinfo.rtnCode) {
case noErr: case noErr:
/* Open a connection */ /* Open a connection */
sock->iopb.ioCompletion = macnet_opened_upp; sock->iopb.ioCompletion = macnet_completed_open_upp;
sock->iopb.csCode = TCPActiveOpen; sock->iopb.csCode = TCPActiveOpen;
sock->iopb.csParam.open.validityFlags = typeOfService; sock->iopb.csParam.open.validityFlags = typeOfService;
sock->iopb.csParam.open.commandTimeoutValue = 0; /* unused */ sock->iopb.csParam.open.commandTimeoutValue = 0; /* unused */
@ -249,14 +256,18 @@ static pascal void macnet_resolved(hostInfo *hi, char *cookie) {
macnet_sendevent(sock, NE_NOHOST); macnet_sendevent(sock, NE_NOHOST);
break; break;
} }
#if !TARGET_RT_CFM
SetA5(olda5); SetA5(olda5);
#endif
} }
static void macnet_opened(TCPiopb *iopb) { static void macnet_completed_open(TCPiopb *iopb) {
Socket *sock = (Socket *)iopb->csParam.open.userDataPtr; Socket *sock = (Socket *)iopb->csParam.open.userDataPtr;
UInt32 olda5; #if !TARGET_RT_CFM
long olda5;
olda5 = SetA5(sock->a5); olda5 = SetA5(sock->a5);
#endif
switch (iopb->ioResult) { switch (iopb->ioResult) {
case noErr: case noErr:
macnet_sendevent(sock, NE_OPEN); macnet_sendevent(sock, NE_OPEN);
@ -265,16 +276,20 @@ static void macnet_opened(TCPiopb *iopb) {
macnet_sendevent(sock, NE_NOOPEN); macnet_sendevent(sock, NE_NOOPEN);
break; break;
} }
#if !TARGET_RT_CFM
SetA5(olda5); SetA5(olda5);
#endif
} }
static pascal void macnet_asr(StreamPtr tcpstream, unsigned short eventcode, static pascal void macnet_asr(StreamPtr tcpstream, unsigned short eventcode,
Ptr cookie, unsigned short terminreason, Ptr cookie, unsigned short terminreason,
ICMPReport *icmpmsg) { ICMPReport *icmpmsg) {
Socket *sock = (Socket *)cookie; Socket *sock = (Socket *)cookie;
UInt32 olda5; #if !TARGET_RT_CFM
long olda5;
olda5 = SetA5(sock->a5); olda5 = SetA5(sock->a5);
#endif
switch (eventcode) { switch (eventcode) {
case TCPClosing: case TCPClosing:
macnet_sendevent(sock, NE_CLOSING); macnet_sendevent(sock, NE_CLOSING);
@ -306,23 +321,87 @@ static pascal void macnet_asr(StreamPtr tcpstream, unsigned short eventcode,
} }
break; break;
} }
#if !TARGET_RT_CFM
SetA5(olda5); SetA5(olda5);
#endif
} }
/* /*
* Send a block of data. * Send a block of data.
*/ */
int net_send(Socket *sock, void *buf, int buflen, int flags) {{ int net_send(Socket *sock, void *buf, int buflen, int flags) {
OSErr err; OSErr err;
Send_Buffer *buff; Send_Buffer *buff;
buff = smalloc(sizeof(Send_Buffer) + buflen); buff = smalloc(sizeof(Send_Buffer) + buflen);
buff->flags = flags; buff->flags = flags;
buff->len = buflen; buff->wds.length = buflen;
memcpy(buff + 1, buf, buflen); buff->wds.ptr = (Ptr)&buff[1]; /* after the end of the struct */
buff->wdsterm = 0;
memcpy(&buff[1], buf, buflen);
Enqueue(&buff->qelem, &sock->sendq); Enqueue(&buff->qelem, &sock->sendq);
macnet_start(sock); /* Kick off the transmit if the queue was empty */
if (sock->sendq.qHead == &buff->qelem)
macnet_startsend(sock);
}
/*
* This is called once every time round the event loop to check for
* network events and handle them.
*/
void macnet_eventcheck() {
NetEvent *ne;
if (!mtcp_initted)
return;
ne = (NetEvent *)macnet_eventq.qHead;
if (ne == NULL)
return;
Dequeue(&ne->qelem, &macnet_eventq);
switch (ne->type) {
case NE_SENT:
macnet_sent(ne->sock);
break;
default:
(ne->sock->s->back->msg)(ne->sock->s, ne->sock, ne->type);
break;
}
Enqueue(&ne->qelem, &macnet_freeq);
}
/*
* The block at the head of the send queue has finished sending, so we
* can free it. Kick off the next transmission if there is one.
*/
static void macnet_sent(Socket *sock) {
Send_Buffer *buff;
assert(sock->sendq.qHead != NULL);
buff = (Send_Buffer *)sock->sendq.qHead;
Dequeue(&buff->qelem, &sock->sendq);
sfree(buff);
if (sock->sendq.qHead != NULL)
macnet_startsend(sock);
}
/*
* There's a block on the head of the send queue which needs to be
* sent.
*/
static void macnet_startsend(Socket *sock) {
Send_Buffer *buff;
OSErr err;
buff = (Send_Buffer *)sock->sendq.qHead;
sock->iopb.csCode = TCPSend;
sock->iopb.csParam.send.validityFlags = 0;
sock->iopb.csParam.send.pushFlag = buff->flags & SEND_PUSH ? true : false;
sock->iopb.csParam.send.urgentFlag = buff->flags & SEND_URG ? true : false;
sock->iopb.csParam.send.wdsPtr = (Ptr)&buff->wds;
sock->iopb.csParam.send.userDataPtr = (char *)sock;
err = PBControlAsync((ParmBlkPtr)&sock->iopb);
} }
int net_recv(Socket *sock, void *buf, int buflen, int flags) { int net_recv(Socket *sock, void *buf, int buflen, int flags) {
@ -331,7 +410,8 @@ int net_recv(Socket *sock, void *buf, int buflen, int flags) {
int avail, want, got; int avail, want, got;
memcpy(&iopb, &sock->iopb, sizeof(TCPiopb)); memcpy(&iopb, &sock->iopb, sizeof(TCPiopb));
/* Work out if there's anything to recieve (we don't want to block) */ /* Work out if there's anything to recieve (we don't want to block)
*/
iopb.csCode = TCPStatus; iopb.csCode = TCPStatus;
err = PBControlSync((ParmBlkPtr)&iopb); err = PBControlSync((ParmBlkPtr)&iopb);
if (err != noErr) if (err != noErr)
@ -341,12 +421,12 @@ int net_recv(Socket *sock, void *buf, int buflen, int flags) {
return 0; return 0;
want = avail < buflen ? avail : buflen; want = avail < buflen ? avail : buflen;
iopb.csCode = TCPRcv; iopb.csCode = TCPRcv;
iopb.csParam.receive.buffPtr = buf; iopb.csParam.receive.rcvBuff = buf;
iopb.csParam.receive.buffLen = want; iopb.csParam.receive.rcvBuffLen = want;
err = PBControlSync((ParmBlkPtr)&iopb); err = PBControlSync((ParmBlkPtr)&iopb);
if (err != noErr) if (err != noErr)
return 0; return 0;
return iopb.csParam.receive.buffLen; return iopb.csParam.receive.rcvBuffLen;
} }
@ -360,7 +440,7 @@ void net_close(Socket *sock) {
* free it, which we can't do at interrupt time). * free it, which we can't do at interrupt time).
*/ */
memcpy(&sock->spareiopb, &sock->iopb, sizeof(TCPiopb)); memcpy(&sock->spareiopb, &sock->iopb, sizeof(TCPiopb));
sock->spareiopb.ioCompletion = macnet_closed_upp; sock->spareiopb.ioCompletion = macnet_completed_close_upp;
sock->spareiopb.csCode = TCPClose; sock->spareiopb.csCode = TCPClose;
sock->spareiopb.csParam.close.validityFlags = 0; sock->spareiopb.csParam.close.validityFlags = 0;
sock->spareiopb.csParam.close.userDataPtr = (char *)sock; sock->spareiopb.csParam.close.userDataPtr = (char *)sock;
@ -376,11 +456,13 @@ void net_close(Socket *sock) {
} }
} }
static void macnet_closed(TCPiopb* iopb) { static void macnet_completed_close(TCPiopb* iopb) {
Socket *sock = (Socket *)iopb->csParam.close.userDataPtr; Socket *sock = (Socket *)iopb->csParam.close.userDataPtr;
UInt32 olda5; #if !TARGET_RT_CFM
long olda5;
olda5 = SetA5(sock->a5); olda5 = SetA5(sock->a5);
#endif
switch (iopb->ioResult) { switch (iopb->ioResult) {
case noErr: case noErr:
macnet_sendevent(sock, NE_CLOSED); macnet_sendevent(sock, NE_CLOSED);
@ -392,7 +474,9 @@ static void macnet_closed(TCPiopb* iopb) {
macnet_sendevent(sock, NE_DIED); macnet_sendevent(sock, NE_DIED);
break; break;
} }
#if !TARGET_RT_CFM
SetA5(olda5); SetA5(olda5);
#endif
} }
/* /*

View File

@ -1,4 +1,4 @@
/* $Id: macterm.c,v 1.1.2.33 1999/03/30 19:44:51 ben Exp $ */ /* $Id: macterm.c,v 1.1.2.34 1999/04/04 18:23:34 ben Exp $ */
/* /*
* Copyright (c) 1999 Simon Tatham * Copyright (c) 1999 Simon Tatham
* Copyright (c) 1999 Ben Harris * Copyright (c) 1999 Ben Harris
@ -140,7 +140,7 @@ void mac_newsession(void) {
s = smalloc(sizeof(*s)); s = smalloc(sizeof(*s));
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
mac_loadconfig(&s->cfg); mac_loadconfig(&s->cfg);
s->back = &hexdump_backend; s->back = &telnet_backend;
/* XXX: Own storage management? */ /* XXX: Own storage management? */
if (mac_gestalts.qdvers == gestaltOriginalQD) if (mac_gestalts.qdvers == gestaltOriginalQD)
@ -158,11 +158,12 @@ void mac_newsession(void) {
SetPalette(s->window, s->palette, TRUE); SetPalette(s->window, s->palette, TRUE);
ActivatePalette(s->window); ActivatePalette(s->window);
ShowWindow(s->window); ShowWindow(s->window);
starttime = TickCount(); s->back->init(s);
display_resource(s, 'pTST', 128); /* starttime = TickCount(); */
sprintf(msg, "Elapsed ticks: %d\015\012", TickCount() - starttime); /* display_resource(s, 'pTST', 128); */
inbuf_putstr(s, msg); /* sprintf(msg, "Elapsed ticks: %d\015\012", TickCount() - starttime); */
term_out(s); /* inbuf_putstr(s, msg); */
/* term_out(s); */
} }
static void mac_initfont(Session *s) { static void mac_initfont(Session *s) {
@ -1011,6 +1012,11 @@ void do_scroll(Session *s, int topline, int botline, int lines) {
DisposeRgn(update); DisposeRgn(update);
} }
void lognegot(/*Session *s,*/ const char *str) {
/* XXX Do something */
}
/* /*
* Emacs magic: * Emacs magic:
* Local Variables: * Local Variables:

20
putty.h
View File

@ -102,6 +102,7 @@ typedef enum {
NE_NOOPEN, /* Connection failed to open for some other reason */ NE_NOOPEN, /* Connection failed to open for some other reason */
NE_DATA, /* Incoming normal data */ NE_DATA, /* Incoming normal data */
NE_URGENT, /* Incoming urgent data */ NE_URGENT, /* Incoming urgent data */
NE_SENT, /* Used internally by Mac network stack */
NE_CLOSING, /* Connection closed by remote host */ NE_CLOSING, /* Connection closed by remote host */
NE_CLOSED, /* Connection close completed */ NE_CLOSED, /* Connection close completed */
NE_TIMEOUT, /* Remote host vanished */ NE_TIMEOUT, /* Remote host vanished */
@ -109,10 +110,14 @@ typedef enum {
NE_DIED, /* Connection has failed for some other reason */ NE_DIED, /* Connection has failed for some other reason */
} Net_Event_Type; } Net_Event_Type;
#ifdef macintosh
typedef Socket *SOCKET;
#define INVALID_SOCKET NULL
#endif
typedef struct { typedef struct {
char *(*init) (Session *, char *host, int port); char *(*init) (Session *);
int (*msg)(Session *, Socket *, Net_Event_Type); int (*msg)(Session *, SOCKET, Net_Event_Type);
void (*send) (Session *, char *buf, int len); void (*send) (Session *, char *buf, int len);
void (*size) (Session *); void (*size) (Session *);
void (*special) (Session *, Telnet_Special code); void (*special) (Session *, Telnet_Special code);
@ -281,14 +286,15 @@ extern void pre_paint(Session *);
extern void post_paint(Session *); extern void post_paint(Session *);
extern void palette_set(Session *, int, int, int, int); extern void palette_set(Session *, int, int, int, int);
extern void palette_reset(Session *); extern void palette_reset(Session *);
void write_clip (void *, int); extern void write_clip (void *, int);
void get_clip (void **, int *); extern void get_clip (void **, int *);
extern void do_scroll(Session *, int, int, int); extern void do_scroll(Session *, int, int, int);
void fatalbox (const char *, ...); extern void fatalbox(const char *, ...);
#ifdef macintosh #ifdef macintosh
#pragma noreturn (fatalbox) #pragma noreturn (fatalbox)
#endif #endif
extern void beep (Session *s); extern void beep(Session *s);
extern void lognegot(const char *);
/* /*
* Exports from the network system * Exports from the network system
@ -298,6 +304,8 @@ extern Socket *net_open(Session *, char *host, int port);
extern char *net_realname(Socket *); extern char *net_realname(Socket *);
extern int net_recv(Socket *, void *, int, int); extern int net_recv(Socket *, void *, int, int);
extern int net_send(Socket *, void *, int, int); extern int net_send(Socket *, void *, int, int);
#define SEND_PUSH 0x01
#define SEND_URG 0x02
extern void net_close(Socket *); /* ask the remote end to close */ extern void net_close(Socket *); /* ask the remote end to close */
extern void net_destroy(Socket *); /* Tidy up */ extern void net_destroy(Socket *); /* Tidy up */

212
telnet.c
View File

@ -1,15 +1,17 @@
#ifdef macintosh #ifdef macintosh
#include <mac.h>
#else /* not macintosh */ #else /* not macintosh */
#include <windows.h> #include <windows.h>
#include <winsock.h> #include <winsock.h>
#endif /* not macintosh */ #endif /* not macintosh */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "putty.h" #include "putty.h"
static SOCKET s = INVALID_SOCKET; static SOCKET s = INVALID_SOCKET;
/* kludge till we decide where to put telnet state */
static Session *sess;
#define IAC 255 /* interpret as command: */ #define IAC 255 /* interpret as command: */
#define DONT 254 /* you are not to use option */ #define DONT 254 /* you are not to use option */
@ -102,7 +104,7 @@ static char *telopt(int opt) {
return "<unknown>"; return "<unknown>";
} }
static void telnet_size(void); static void telnet_size(Session *ignored);
struct Opt { struct Opt {
int send; /* what we initially send */ int send; /* what we initially send */
@ -135,19 +137,19 @@ static int in_synch;
#endif #endif
static int sb_opt, sb_len; static int sb_opt, sb_len;
static char *sb_buf = NULL; static unsigned char *sb_buf = NULL;
static int sb_size = 0; static int sb_size = 0;
#define SB_DELTA 1024 #define SB_DELTA 1024
static void try_write (void) { static void try_write (void) {
while (outbuf_head != outbuf_reap) { while (sess->outbuf_head != sess->outbuf_reap) {
int end = (outbuf_reap < outbuf_head ? outbuf_head : OUTBUF_SIZE); int end = (sess->outbuf_reap < sess->outbuf_head ? sess->outbuf_head : OUTBUF_SIZE);
int len = end - outbuf_reap; int len = end - sess->outbuf_reap;
int ret; int ret;
ret = send (s, outbuf+outbuf_reap, len, 0); ret = net_send (s, sess->outbuf+sess->outbuf_reap, len, 0);
if (ret > 0) if (ret > 0)
outbuf_reap = (outbuf_reap + ret) & OUTBUF_MASK; sess->outbuf_reap = (sess->outbuf_reap + ret) & OUTBUF_MASK;
if (ret < len) if (ret < len)
return; return;
} }
@ -156,10 +158,10 @@ static void try_write (void) {
static void s_write (void *buf, int len) { static void s_write (void *buf, int len) {
unsigned char *p = buf; unsigned char *p = buf;
while (len--) { while (len--) {
int new_head = (outbuf_head + 1) & OUTBUF_MASK; int new_head = (sess->outbuf_head + 1) & OUTBUF_MASK;
if (new_head != outbuf_reap) { if (new_head != sess->outbuf_reap) {
outbuf[outbuf_head] = *p++; sess->outbuf[sess->outbuf_head] = *p++;
outbuf_head = new_head; sess->outbuf_head = new_head;
} }
} }
try_write(); try_write();
@ -167,11 +169,11 @@ static void s_write (void *buf, int len) {
static void c_write (char *buf, int len) { static void c_write (char *buf, int len) {
while (len--) { while (len--) {
int new_head = (inbuf_head + 1) & INBUF_MASK; int new_head = (sess->inbuf_head + 1) & INBUF_MASK;
int c = (unsigned char) *buf; int c = (unsigned char) *buf;
if (new_head != inbuf_reap) { if (new_head != sess->inbuf_reap) {
inbuf[inbuf_head] = *buf++; sess->inbuf[sess->inbuf_head] = *buf++;
inbuf_head = new_head; sess->inbuf_head = new_head;
} }
} }
} }
@ -201,7 +203,7 @@ static void deactivate_option (struct Opt *o) {
static void activate_option (struct Opt *o) { static void activate_option (struct Opt *o) {
if (o->send == WILL && o->option == TELOPT_NAWS) if (o->send == WILL && o->option == TELOPT_NAWS)
telnet_size(); telnet_size(sess);
if (o->send == WILL && if (o->send == WILL &&
(o->option == TELOPT_NEW_ENVIRON || (o->option == TELOPT_NEW_ENVIRON ||
o->option == TELOPT_OLD_ENVIRON)) { o->option == TELOPT_OLD_ENVIRON)) {
@ -276,27 +278,27 @@ static void process_subneg (void) {
switch (sb_opt) { switch (sb_opt) {
case TELOPT_TSPEED: case TELOPT_TSPEED:
if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) { if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) {
char logbuf[sizeof(cfg.termspeed)+80]; char logbuf[sizeof(sess->cfg.termspeed)+80];
b[0] = IAC; b[1] = SB; b[2] = TELOPT_TSPEED; b[0] = IAC; b[1] = SB; b[2] = TELOPT_TSPEED;
b[3] = TELQUAL_IS; b[3] = TELQUAL_IS;
strcpy(b+4, cfg.termspeed); strcpy((char *)b+4, sess->cfg.termspeed);
n = 4 + strlen(cfg.termspeed); n = 4 + strlen(sess->cfg.termspeed);
b[n] = IAC; b[n+1] = SE; b[n] = IAC; b[n+1] = SE;
s_write (b, n+2); s_write (b, n+2);
lognegot("server:\tSB TSPEED SEND"); lognegot("server:\tSB TSPEED SEND");
sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed); sprintf(logbuf, "client:\tSB TSPEED IS %s", sess->cfg.termspeed);
lognegot (logbuf); lognegot (logbuf);
} else } else
lognegot ("server:\tSB TSPEED <something weird>"); lognegot ("server:\tSB TSPEED <something weird>");
break; break;
case TELOPT_TTYPE: case TELOPT_TTYPE:
if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) { if (sb_len == 1 && sb_buf[0] == TELQUAL_SEND) {
char logbuf[sizeof(cfg.termtype)+80]; char logbuf[sizeof(sess->cfg.termtype)+80];
b[0] = IAC; b[1] = SB; b[2] = TELOPT_TTYPE; b[0] = IAC; b[1] = SB; b[2] = TELOPT_TTYPE;
b[3] = TELQUAL_IS; b[3] = TELQUAL_IS;
for (n = 0; cfg.termtype[n]; n++) for (n = 0; sess->cfg.termtype[n]; n++)
b[n+4] = (cfg.termtype[n] >= 'a' && cfg.termtype[n] <= 'z' ? b[n+4] = (sess->cfg.termtype[n] >= 'a' && sess->cfg.termtype[n] <= 'z' ?
cfg.termtype[n] + 'A'-'a' : cfg.termtype[n]); sess->cfg.termtype[n] + 'A'-'a' : sess->cfg.termtype[n]);
b[n+4] = IAC; b[n+5] = SE; b[n+4] = IAC; b[n+5] = SE;
s_write (b, n+6); s_write (b, n+6);
b[n+4] = 0; b[n+4] = 0;
@ -316,7 +318,7 @@ static void process_subneg (void) {
sprintf (logbuf, "server:\tSB %s SEND", telopt(sb_opt)); sprintf (logbuf, "server:\tSB %s SEND", telopt(sb_opt));
lognegot (logbuf); lognegot (logbuf);
if (sb_opt == TELOPT_OLD_ENVIRON) { if (sb_opt == TELOPT_OLD_ENVIRON) {
if (cfg.rfc_environ) { if (sess->cfg.rfc_environ) {
value = RFC_VALUE; value = RFC_VALUE;
var = RFC_VAR; var = RFC_VAR;
} else { } else {
@ -347,7 +349,7 @@ static void process_subneg (void) {
b[0] = IAC; b[1] = SB; b[2] = sb_opt; b[0] = IAC; b[1] = SB; b[2] = sb_opt;
b[3] = TELQUAL_IS; b[3] = TELQUAL_IS;
n = 4; n = 4;
e = cfg.environmt; e = sess->cfg.environmt;
while (*e) { while (*e) {
b[n++] = var; b[n++] = var;
while (*e && *e != '\t') b[n++] = *e++; while (*e && *e != '\t') b[n++] = *e++;
@ -356,10 +358,10 @@ static void process_subneg (void) {
while (*e) b[n++] = *e++; while (*e) b[n++] = *e++;
e++; e++;
} }
if (*cfg.username) { if (*sess->cfg.username) {
b[n++] = var; b[n++] = 'U'; b[n++] = 'S'; b[n++] = var; b[n++] = 'U'; b[n++] = 'S';
b[n++] = 'E'; b[n++] = 'R'; b[n++] = value; b[n++] = 'E'; b[n++] = 'R'; b[n++] = value;
e = cfg.username; e = sess->cfg.username;
while (*e) b[n++] = *e++; while (*e) b[n++] = *e++;
} }
b[n++] = IAC; b[n++] = SE; b[n++] = IAC; b[n++] = SE;
@ -373,9 +375,9 @@ static void process_subneg (void) {
} }
static enum { static enum {
TOPLEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT, TELNET_TOPLEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT,
SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR
} telnet_state = TOPLEVEL; } telnet_state = TELNET_TOPLEVEL;
static void do_telnet_read (char *buf, int len) { static void do_telnet_read (char *buf, int len) {
unsigned char b[10]; unsigned char b[10];
@ -384,10 +386,10 @@ static void do_telnet_read (char *buf, int len) {
int c = (unsigned char) *buf++; int c = (unsigned char) *buf++;
switch (telnet_state) { switch (telnet_state) {
case TOPLEVEL: case TELNET_TOPLEVEL:
case SEENCR: case SEENCR:
if (c == NUL && telnet_state == SEENCR) if (c == NUL && telnet_state == SEENCR)
telnet_state = TOPLEVEL; telnet_state = TELNET_TOPLEVEL;
else if (c == IAC) else if (c == IAC)
telnet_state = SEENIAC; telnet_state = SEENIAC;
else { else {
@ -395,11 +397,11 @@ static void do_telnet_read (char *buf, int len) {
#if 0 #if 0
if (!in_synch) if (!in_synch)
#endif #endif
c_write (b, 1); c_write ((char *)b, 1);
if (c == CR) if (c == CR)
telnet_state = SEENCR; telnet_state = SEENCR;
else else
telnet_state = TOPLEVEL; telnet_state = TELNET_TOPLEVEL;
} }
break; break;
case SEENIAC: case SEENIAC:
@ -408,23 +410,23 @@ static void do_telnet_read (char *buf, int len) {
else if (c == WILL) telnet_state = SEENWILL; else if (c == WILL) telnet_state = SEENWILL;
else if (c == WONT) telnet_state = SEENWONT; else if (c == WONT) telnet_state = SEENWONT;
else if (c == SB) telnet_state = SEENSB; else if (c == SB) telnet_state = SEENSB;
else telnet_state = TOPLEVEL;/* ignore _everything_ else! */ else telnet_state = TELNET_TOPLEVEL;/* ignore _everything_ else! */
break; break;
case SEENWILL: case SEENWILL:
proc_rec_opt (WILL, c); proc_rec_opt (WILL, c);
telnet_state = TOPLEVEL; telnet_state = TELNET_TOPLEVEL;
break; break;
case SEENWONT: case SEENWONT:
proc_rec_opt (WONT, c); proc_rec_opt (WONT, c);
telnet_state = TOPLEVEL; telnet_state = TELNET_TOPLEVEL;
break; break;
case SEENDO: case SEENDO:
proc_rec_opt (DO, c); proc_rec_opt (DO, c);
telnet_state = TOPLEVEL; telnet_state = TELNET_TOPLEVEL;
break; break;
case SEENDONT: case SEENDONT:
proc_rec_opt (DONT, c); proc_rec_opt (DONT, c);
telnet_state = TOPLEVEL; telnet_state = TELNET_TOPLEVEL;
break; break;
case SEENSB: case SEENSB:
sb_opt = c; sb_opt = c;
@ -437,7 +439,7 @@ static void do_telnet_read (char *buf, int len) {
else { else {
subneg_addchar: subneg_addchar:
if (sb_len >= sb_size) { if (sb_len >= sb_size) {
char *newbuf; unsigned char *newbuf;
sb_size += SB_DELTA; sb_size += SB_DELTA;
newbuf = (sb_buf ? newbuf = (sb_buf ?
realloc(sb_buf, sb_size) : realloc(sb_buf, sb_size) :
@ -457,7 +459,7 @@ static void do_telnet_read (char *buf, int len) {
goto subneg_addchar; /* yes, it's a hack, I know, but... */ goto subneg_addchar; /* yes, it's a hack, I know, but... */
else { else {
process_subneg(); process_subneg();
telnet_state = TOPLEVEL; telnet_state = TELNET_TOPLEVEL;
} }
break; break;
} }
@ -471,84 +473,11 @@ static void do_telnet_read (char *buf, int len) {
* *
* Returns an error message, or NULL on success. * Returns an error message, or NULL on success.
* *
* Also places the canonical host name into `realhost'.
*/ */
static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) { static char *telnet_init (Session *this_sess) {
SOCKADDR_IN addr;
struct hostent *h;
unsigned long a;
/* sess = this_sess;
* Try to find host. s = net_open(sess, sess->cfg.host, sess->cfg.port);
*/
if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
if ( (h = gethostbyname(host)) == NULL)
switch (WSAGetLastError()) {
case WSAENETDOWN: return "Network is down";
case WSAHOST_NOT_FOUND: case WSANO_DATA:
return "Host does not exist";
case WSATRY_AGAIN: return "Host not found";
default: return "gethostbyname: unknown error";
}
memcpy (&a, h->h_addr, sizeof(a));
*realhost = h->h_name;
} else
*realhost = host;
a = ntohl(a);
if (port < 0)
port = 23; /* default telnet port */
/*
* Open socket.
*/
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET)
switch (WSAGetLastError()) {
case WSAENETDOWN: return "Network is down";
case WSAEAFNOSUPPORT: return "TCP/IP support not present";
default: return "socket(): unknown error";
}
#if 0
{
BOOL b = TRUE;
setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (void *)&b, sizeof(b));
}
#endif
/*
* Bind to local address.
*/
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(0);
if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
switch (WSAGetLastError()) {
case WSAENETDOWN: return "Network is down";
default: return "bind(): unknown error";
}
/*
* Connect to remote address.
*/
addr.sin_addr.s_addr = htonl(a);
addr.sin_port = htons((short)port);
if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
switch (WSAGetLastError()) {
case WSAENETDOWN: return "Network is down";
case WSAECONNREFUSED: return "Connection refused";
case WSAENETUNREACH: return "Network is unreachable";
case WSAEHOSTUNREACH: return "No route to host";
default: return "connect(): unknown error";
}
if (WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ |
FD_WRITE | FD_OOB | FD_CLOSE) == SOCKET_ERROR)
switch (WSAGetLastError()) {
case WSAENETDOWN: return "Network is down";
default: return "WSAAsyncSelect(): unknown error";
}
/* /*
* Initialise option states. * Initialise option states.
@ -575,23 +504,18 @@ static char *telnet_init (HWND hwnd, char *host, int port, char **realhost) {
* Process a WM_NETEVENT message. Will return 0 if the connection * Process a WM_NETEVENT message. Will return 0 if the connection
* has closed, or <0 for a socket error. * has closed, or <0 for a socket error.
*/ */
static int telnet_msg (WPARAM wParam, LPARAM lParam) { static int telnet_msg (Session *sess, SOCKET sock, Net_Event_Type ne) {
int ret; int ret;
char buf[256]; char buf[256];
if (s == INVALID_SOCKET) /* how the hell did we get here?! */ if (s == INVALID_SOCKET) /* how the hell did we get here?! */
return -5000; return -5000;
if (WSAGETSELECTERROR(lParam) != 0) switch (ne) {
return -WSAGETSELECTERROR(lParam); case NE_DATA:
ret = net_recv(s, buf, sizeof(buf), 0);
switch (WSAGETSELECTEVENT(lParam)) {
case FD_READ:
ret = recv(s, buf, sizeof(buf), 0);
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
return 1;
if (ret < 0) /* any _other_ error */ if (ret < 0) /* any _other_ error */
return -10000-WSAGetLastError(); return -1;
if (ret == 0) { if (ret == 0) {
s = INVALID_SOCKET; s = INVALID_SOCKET;
return 0; /* can't happen, in theory */ return 0; /* can't happen, in theory */
@ -608,24 +532,20 @@ static int telnet_msg (WPARAM wParam, LPARAM lParam) {
#endif #endif
do_telnet_read (buf, ret); do_telnet_read (buf, ret);
return 1; return 1;
case FD_OOB: case NE_URGENT:
do { do {
ret = recv(s, buf, sizeof(buf), 0); ret = net_recv(s, buf, sizeof(buf), 0);
} while (ret > 0); } while (ret > 0);
telnet_state = TOPLEVEL; telnet_state = TELNET_TOPLEVEL;
do { do {
ret = recv(s, buf, 1, MSG_OOB); ret = net_recv(s, buf, 1, /*MSG_OOB*/ 0);
if (ret > 0) if (ret > 0)
do_telnet_read (buf, ret); do_telnet_read (buf, ret);
} while (ret > 0); } while (ret > 0);
if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) if (ret < 0)
return -30000-WSAGetLastError(); return -3;
return 1; return 1;
case FD_WRITE: case NE_CLOSING:
if (outbuf_head != outbuf_reap)
try_write();
return 1;
case FD_CLOSE:
s = INVALID_SOCKET; s = INVALID_SOCKET;
return 0; return 0;
} }
@ -635,7 +555,7 @@ static int telnet_msg (WPARAM wParam, LPARAM lParam) {
/* /*
* Called to send data down the Telnet connection. * Called to send data down the Telnet connection.
*/ */
static void telnet_send (char *buf, int len) { static void telnet_send (Session *this_sess, char *buf, int len) {
char *p; char *p;
static unsigned char iac[2] = { IAC, IAC }; static unsigned char iac[2] = { IAC, IAC };
static unsigned char cr[2] = { CR, NUL }; static unsigned char cr[2] = { CR, NUL };
@ -660,15 +580,15 @@ static void telnet_send (char *buf, int len) {
/* /*
* Called to set the size of the window from Telnet's POV. * Called to set the size of the window from Telnet's POV.
*/ */
static void telnet_size(void) { static void telnet_size(Session *sess) {
unsigned char b[16]; unsigned char b[16];
char logbuf[50]; char logbuf[50];
if (s == INVALID_SOCKET || o_naws.state != ACTIVE) if (s == INVALID_SOCKET || o_naws.state != ACTIVE)
return; return;
b[0] = IAC; b[1] = SB; b[2] = TELOPT_NAWS; b[0] = IAC; b[1] = SB; b[2] = TELOPT_NAWS;
b[3] = cols >> 8; b[4] = cols & 0xFF; b[3] = sess->cols >> 8; b[4] = sess->cols & 0xFF;
b[5] = rows >> 8; b[6] = rows & 0xFF; b[5] = sess->rows >> 8; b[6] = sess->rows & 0xFF;
b[7] = IAC; b[8] = SE; b[7] = IAC; b[8] = SE;
s_write (b, 9); s_write (b, 9);
sprintf(logbuf, "client:\tSB NAWS %d,%d", sprintf(logbuf, "client:\tSB NAWS %d,%d",
@ -680,7 +600,7 @@ static void telnet_size(void) {
/* /*
* Send Telnet special codes. * Send Telnet special codes.
*/ */
static void telnet_special (Telnet_Special code) { static void telnet_special (Session *sess, Telnet_Special code) {
unsigned char b[2]; unsigned char b[2];
if (s == INVALID_SOCKET) if (s == INVALID_SOCKET)
@ -701,9 +621,9 @@ static void telnet_special (Telnet_Special code) {
case TS_EOR: b[1] = EOR; s_write (b, 2); break; case TS_EOR: b[1] = EOR; s_write (b, 2); break;
case TS_EOF: b[1] = xEOF; s_write (b, 2); break; case TS_EOF: b[1] = xEOF; s_write (b, 2); break;
case TS_SYNCH: case TS_SYNCH:
outbuf_head = outbuf_reap = 0; sess->outbuf_head = sess->outbuf_reap = 0;
b[0] = DM; b[0] = DM;
send (s, b, 1, MSG_OOB); net_send (s, b, 1, SEND_URG);
break; break;
} }
} }

View File

@ -1,4 +1,4 @@
/* $Id: testback.c,v 1.1.2.5 1999/03/29 19:50:24 ben Exp $ */ /* $Id: testback.c,v 1.1.2.6 1999/04/04 18:23:35 ben Exp $ */
/* /*
* Copyright (c) 1999 Simon Tatham * Copyright (c) 1999 Simon Tatham
* Copyright (c) 1999 Ben Harris * Copyright (c) 1999 Ben Harris
@ -33,8 +33,8 @@
#include "putty.h" #include "putty.h"
static char *null_init(Session *, char *, int, char **); static char *null_init(Session *);
static int null_msg(Session *); static int null_msg(Session *, Socket *, Net_Event_Type);
static void null_send(Session *, char *, int); static void null_send(Session *, char *, int);
static void loop_send(Session *, char *, int); static void loop_send(Session *, char *, int);
static void hexdump_send(Session *, char *, int); static void hexdump_send(Session *, char *, int);
@ -53,12 +53,12 @@ Backend hexdump_backend = {
null_init, null_msg, hexdump_send, null_size, null_special null_init, null_msg, hexdump_send, null_size, null_special
}; };
static char *null_init(Session *s, char *host, int port, char **realhost) { static char *null_init(Session *s) {
return NULL; return NULL;
} }
static int null_msg(Session *s) { static int null_msg(Session *s, Socket *sock, Net_Event_Type ne) {
return 1; return 1;
} }