mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Yeah. Some progress on Mac OS networking. Still some way to go, though.
[originally from svn r155]
This commit is contained in:
parent
05e93b3d2b
commit
efc9e4260c
@ -1,4 +1,4 @@
|
||||
# $Id: Makefile.mpw,v 1.1.2.10 1999/04/02 12:56:57 ben Exp $
|
||||
# $Id: Makefile.mpw,v 1.1.2.11 1999/04/03 21:53:29 ben Exp $
|
||||
# This is the Makefile for building PuTTY for the Mac OS.
|
||||
# Users of non-Mac systems will see some pretty strange characters around.
|
||||
|
||||
@ -120,6 +120,7 @@ PuTTY
|
||||
|
||||
mac.c.o mac.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
|
||||
macterm.c.o macterm.c.x Ä putty.h mac.h
|
||||
misc.c.o misc.c.x Ä putty.h
|
||||
ssh.c.o ssh.c.x Ä putty.h ssh.h
|
||||
|
382
macnet.c
382
macnet.c
@ -1,4 +1,4 @@
|
||||
/* $Id: macnet.c,v 1.1.2.1 1999/04/01 21:26:03 ben Exp $ */
|
||||
/* $Id: macnet.c,v 1.1.2.2 1999/04/03 21:53:29 ben Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1999 Ben Harris
|
||||
* All rights reserved.
|
||||
@ -29,70 +29,402 @@
|
||||
*/
|
||||
|
||||
#include <MacTypes.h>
|
||||
#include <AddresXlation.h>
|
||||
#incldue <MacTCP.h>
|
||||
#include <AddressXlation.h>
|
||||
#include <Devices.h>
|
||||
#include <MacTCP.h>
|
||||
#include <MixedMode.h>
|
||||
#include <OSUtils.h>
|
||||
#include <Processes.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "putty.h"
|
||||
|
||||
/*
|
||||
* The theory behind this stuff:
|
||||
*
|
||||
* net_recv attempts to deliver any incoming data waiting on the
|
||||
* queue. Since MacTCP maintains a buffer for incoming data, there's
|
||||
* no need for us to run asynchronous TCPRcvs, and we just do a
|
||||
* synchronous one if we detect some data waiting. Since TCPRcv can't
|
||||
* be given a timeout of zero, we use TCPStatus to work out if there's
|
||||
* anything waiting first.
|
||||
*
|
||||
* Sending data is trickier. TCPSend reserves the right to block
|
||||
* until everything we've sent is ACKed, which means we have to use it
|
||||
* asynchronously. In order to make life easier for backends, and to
|
||||
* save a proliferation of circular buffers, we guarantee to take data
|
||||
* off the hands of the backend as soon as it gives it to us. This is
|
||||
* reasonable because currently there's no way for the backend to say
|
||||
* it can't take data, and once it's got them, it may as well give
|
||||
* them to us.
|
||||
*
|
||||
* Anyway, in order to avoid a fixed-size buffer overflowing, the send
|
||||
* buffer is kept as a queue of blocks. When net_send is called, we
|
||||
* malloc a new block and stick it on the queue. If the queue was
|
||||
* empty, we kick off a new asynchronous TCPSend to handle our block.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct Socket {
|
||||
TCPiopb iopb; /* current MacTCP operation */
|
||||
TCPiopb spareiopb; /* for closing etc */
|
||||
hostInfo hostinfo;
|
||||
int port;
|
||||
// unsigned char *inbuf;
|
||||
// int inbuf_head, inbuf_reap, inbuf_size;
|
||||
// unsigned char *outbuf;
|
||||
// int outbuf_head, outbuf_reap, outbuf_size;
|
||||
ProcessSerialNumber psn;
|
||||
Session *s;
|
||||
UInt32 a5;
|
||||
qHdr sendq; /* Blocks waiting to be sent */
|
||||
qHdr freeq; /* Blocks sent, waiting to be freed */
|
||||
} Socket;
|
||||
|
||||
typedef struct {
|
||||
QElem qelem;
|
||||
int flags;
|
||||
int len;
|
||||
} Send_Buffer;
|
||||
|
||||
/*
|
||||
* Yes, I know the struct QElem has a short[1] to represent the user
|
||||
* data. I'm ignoring it because it makes my code prettier and
|
||||
* improves the alignment.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
QElem qelem;
|
||||
Socket *sock;
|
||||
Net_Event_Type type;
|
||||
} NetEvent;
|
||||
|
||||
#define TCPBUF_SIZE 8192
|
||||
|
||||
static QHdr macnet_eventq;
|
||||
static QHdr macnet_freeq;
|
||||
|
||||
static short mtcp_refnum;
|
||||
statis OSErr mtcp_initted = FALSE;
|
||||
static int mtcp_initted = FALSE;
|
||||
|
||||
static void macnet_init(void);
|
||||
static pascal void macnet_resolved(struct HostInfo *, char *);
|
||||
static OSErr macnet_init(void);
|
||||
static pascal void macnet_resolved(hostInfo *, char *);
|
||||
static void macnet_opened(TCPiopb*);
|
||||
static void macnet_sent(TCPiopb*);
|
||||
static void macnet_closed(TCPiopb*);
|
||||
static pascal void macnet_asr(StreamPtr, unsigned short, Ptr, unsigned short,
|
||||
ICMPReport *);
|
||||
static void macnet_sendevent(Socket *, Net_Event_Type);
|
||||
|
||||
#ifdef TARGET_RT_MAC_CFM
|
||||
#if TARGET_RT_MAC_CFM
|
||||
static RoutineDescriptor macnet_resolved_upp =
|
||||
BUILD_ROUTINE_DESCRIPTOR(uppResultProcInfo, (ProcPtr)macnet_resolved);
|
||||
static RoutineDescriptor macnet_opened_upp =
|
||||
BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo,
|
||||
(ProcPtr)macnet_opened);
|
||||
static RoutineDescriptor macnet_sent_upp =
|
||||
BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo, (ProcPtr)macnet_sent);
|
||||
static RoutineDescriptor macnet_closed_upp =
|
||||
BUILD_ROUTINE_DESCRIPTOR(uppTCPIOCompletionProcInfo,
|
||||
(ProcPtr)macnet_closed);
|
||||
static RoutineDescriptor macnet_asr_upp =
|
||||
BUILD_ROUTINE_DESCRIPTOR(uppTCPNotifyProcInfo, (ProcPtr)macnet_asr);
|
||||
#else
|
||||
#define macnet_resolved_upp macnet_resolved
|
||||
#define macnet_opened_upp macnet_opened
|
||||
#define macnet_sent_upp macnet_sent
|
||||
#define macnet_closed_upp macnet_closed
|
||||
#define macnet_asr_upp macnet_asr
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Number of outstanding network events allowed.
|
||||
*/
|
||||
#define NUM_EVENTS 16
|
||||
|
||||
/*
|
||||
* Initialise networking. Set mtcp_initted if it goes OK.
|
||||
*/
|
||||
static OSErr macnet_init(void) {
|
||||
OSErr err;
|
||||
NetEvent *eventblock;
|
||||
int i;
|
||||
|
||||
err = OpenDriver(".IPP", &mtcp_refnum);
|
||||
err = opendriver(".IPP", &mtcp_refnum);
|
||||
if (err != noErr)
|
||||
return err;
|
||||
err = OpenResolver(NULL);
|
||||
if (err != noErr)
|
||||
return err;
|
||||
/* Set up the event queues, and fill the free queue with events */
|
||||
macnet_eventq.qFlags = 0;
|
||||
macnet_eventq.qHead = macnet_eventq.qTail = NULL;
|
||||
macnet_freeq.qFlags = 0;
|
||||
macnet_freeq.qHead = macnet_eventq.qTail = NULL;
|
||||
eventblock = smalloc(NUM_EVENTS * sizeof(NetEvent));
|
||||
for (i = 0; i < NUM_EVENTS; i++)
|
||||
Enqueue(&eventblock[i].qelem, &macnet_freeq);
|
||||
mtcp_initted = TRUE;
|
||||
|
||||
/* XXX: otherwise report an error */
|
||||
}
|
||||
|
||||
Socket *tcp_open(const char *host, int port, char **realhost) {
|
||||
Socket *net_open(Session *s, char *host, int port) {
|
||||
ip_addr a;
|
||||
OSError err = noErr;
|
||||
Socket *s;
|
||||
OSErr err = noErr;
|
||||
Socket *sock;
|
||||
void *tcpbuf;
|
||||
|
||||
s = smalloc(sizeof(struct Socket));
|
||||
/*
|
||||
* First, get hold of all the memory we'll need (a lot of the
|
||||
* later stuff happens at interrupt time)
|
||||
*/
|
||||
sock = smalloc(sizeof(struct Socket));
|
||||
memset(sock, 0, sizeof(*sock));
|
||||
tcpbuf = smalloc(TCPBUF_SIZE);
|
||||
|
||||
/* Make a note of anything we don't want to forget */
|
||||
sock->port = port;
|
||||
GetCurrentProcess(&sock->psn);
|
||||
sock->a5 = SetCurrentA5();
|
||||
|
||||
/* Get MacTCP running if it's not already */
|
||||
if (!mtcp_initted)
|
||||
if ((err = macnet_init()) != noErr)
|
||||
fatalbox("Couldn't init network (%d)", err);
|
||||
s->port = port;
|
||||
GetCurrentProcess(&s->psn);
|
||||
err = StrToAddr(host, &s->host_info, &macnet_resolved_upp, (char *)s);
|
||||
|
||||
/* Get ourselves a TCP stream to play with */
|
||||
sock->iopb.ioCRefNum = mtcp_refnum;
|
||||
sock->iopb.csCode = TCPCreate;
|
||||
sock->iopb.csParam.create.rcvBuff = tcpbuf;
|
||||
sock->iopb.csParam.create.rcvBuffLen = TCPBUF_SIZE;
|
||||
sock->iopb.csParam.create.notifyProc = macnet_asr_upp;
|
||||
sock->iopb.csParam.create.userDataPtr = (Ptr)sock;
|
||||
/* This could be done asynchronously, but I doubt it'll take long. */
|
||||
err = PBControlSync((ParmBlkPtr)&sock->iopb);
|
||||
if (err != noErr)
|
||||
fatalbox("TCP stream open failed (%d)", err);
|
||||
|
||||
err = StrToAddr(host, &sock->hostinfo, &macnet_resolved_upp, (char *)sock);
|
||||
if (err != noErr)
|
||||
fatalbox("Host lookup failed (%d)", err);
|
||||
if (s->host_info.rtnCode != cacheFault)
|
||||
macnet_resolved(&s->host_info, s);
|
||||
return s;
|
||||
if (sock->hostinfo.rtnCode != cacheFault)
|
||||
macnet_resolved(&sock->hostinfo, (char *)sock);
|
||||
return sock;
|
||||
}
|
||||
|
||||
static pascal void macnet_resolved(struct hostInfo *hi, char *cookie) {
|
||||
Socket *s = (Socket *)cookie;
|
||||
static pascal void macnet_resolved(hostInfo *hi, char *cookie) {
|
||||
Socket *sock = (Socket *)cookie;
|
||||
OSErr err;
|
||||
UInt32 olda5;
|
||||
|
||||
/* We should probably tell the process what's going on here. */
|
||||
/* Alternatively, we should kick off the next stage in the process */
|
||||
WakeUpProcess(&s->psn);
|
||||
olda5 = SetA5(sock->a5);
|
||||
/*
|
||||
* We've resolved a name, so now we'd like to connect to it (or
|
||||
* report an error).
|
||||
*/
|
||||
switch (sock->hostinfo.rtnCode) {
|
||||
case noErr:
|
||||
/* Open a connection */
|
||||
sock->iopb.ioCompletion = macnet_opened_upp;
|
||||
sock->iopb.csCode = TCPActiveOpen;
|
||||
sock->iopb.csParam.open.validityFlags = typeOfService;
|
||||
sock->iopb.csParam.open.commandTimeoutValue = 0; /* unused */
|
||||
sock->iopb.csParam.open.remoteHost = sock->hostinfo.addr[0]; /*XXX*/
|
||||
sock->iopb.csParam.open.remotePort = sock->port;
|
||||
/* localHost is set by MacTCP. */
|
||||
sock->iopb.csParam.open.localPort = 0;
|
||||
sock->iopb.csParam.open.tosFlags = lowDelay;
|
||||
sock->iopb.csParam.open.dontFrag = 0;
|
||||
sock->iopb.csParam.open.timeToLive = 0; /* default */
|
||||
sock->iopb.csParam.open.security = 0;
|
||||
sock->iopb.csParam.open.optionCnt = 0;
|
||||
sock->iopb.csParam.open.userDataPtr = (char *)sock;
|
||||
err = PBControlSync((ParmBlkPtr)&sock->iopb);
|
||||
if (err != noErr)
|
||||
macnet_sendevent(sock, NE_NOOPEN);
|
||||
break;
|
||||
default: /* Something went wrong */
|
||||
macnet_sendevent(sock, NE_NOHOST);
|
||||
break;
|
||||
}
|
||||
SetA5(olda5);
|
||||
}
|
||||
|
||||
static void macnet_opened(TCPiopb *iopb) {
|
||||
Socket *sock = (Socket *)iopb->csParam.open.userDataPtr;
|
||||
UInt32 olda5;
|
||||
|
||||
olda5 = SetA5(sock->a5);
|
||||
switch (iopb->ioResult) {
|
||||
case noErr:
|
||||
macnet_sendevent(sock, NE_OPEN);
|
||||
break;
|
||||
default:
|
||||
macnet_sendevent(sock, NE_NOOPEN);
|
||||
break;
|
||||
}
|
||||
SetA5(olda5);
|
||||
}
|
||||
|
||||
static pascal void macnet_asr(StreamPtr tcpstream, unsigned short eventcode,
|
||||
Ptr cookie, unsigned short terminreason,
|
||||
ICMPReport *icmpmsg) {
|
||||
Socket *sock = (Socket *)cookie;
|
||||
UInt32 olda5;
|
||||
|
||||
olda5 = SetA5(sock->a5);
|
||||
switch (eventcode) {
|
||||
case TCPClosing:
|
||||
macnet_sendevent(sock, NE_CLOSING);
|
||||
break;
|
||||
case TCPULPTimeout:
|
||||
macnet_sendevent(sock, NE_TIMEOUT);
|
||||
break;
|
||||
case TCPTerminate:
|
||||
switch (terminreason) {
|
||||
case TCPRemoteAbort:
|
||||
macnet_sendevent(sock, NE_ABORT);
|
||||
break;
|
||||
default:
|
||||
macnet_sendevent(sock, NE_DIED);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TCPDataArrival:
|
||||
macnet_sendevent(sock, NE_DATA);
|
||||
break;
|
||||
case TCPUrgent:
|
||||
macnet_sendevent(sock, NE_URGENT);
|
||||
break;
|
||||
case TCPICMPReceived:
|
||||
switch (icmpmsg->reportType) {
|
||||
case portUnreach:
|
||||
macnet_sendevent(sock, NE_REFUSED);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
SetA5(olda5);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a block of data.
|
||||
*/
|
||||
|
||||
int net_send(Socket *sock, void *buf, int buflen, int flags) {{
|
||||
OSErr err;
|
||||
Send_Buffer *buff;
|
||||
|
||||
buff = smalloc(sizeof(Send_Buffer) + buflen);
|
||||
buff->flags = flags;
|
||||
buff->len = buflen;
|
||||
memcpy(buff + 1, buf, buflen);
|
||||
Enqueue(&buff->qelem, &sock->sendq);
|
||||
macnet_start(sock);
|
||||
}
|
||||
|
||||
int net_recv(Socket *sock, void *buf, int buflen, int flags) {
|
||||
TCPiopb iopb;
|
||||
OSErr err;
|
||||
int avail, want, got;
|
||||
|
||||
memcpy(&iopb, &sock->iopb, sizeof(TCPiopb));
|
||||
/* Work out if there's anything to recieve (we don't want to block) */
|
||||
iopb.csCode = TCPStatus;
|
||||
err = PBControlSync((ParmBlkPtr)&iopb);
|
||||
if (err != noErr)
|
||||
return 0; /* macnet_asr should catch it anyway */
|
||||
avail = iopb.csParam.status.amtUnreadData;
|
||||
if (avail == 0)
|
||||
return 0;
|
||||
want = avail < buflen ? avail : buflen;
|
||||
iopb.csCode = TCPRcv;
|
||||
iopb.csParam.receive.buffPtr = buf;
|
||||
iopb.csParam.receive.buffLen = want;
|
||||
err = PBControlSync((ParmBlkPtr)&iopb);
|
||||
if (err != noErr)
|
||||
return 0;
|
||||
return iopb.csParam.receive.buffLen;
|
||||
}
|
||||
|
||||
|
||||
void net_close(Socket *sock) {
|
||||
OSErr err;
|
||||
|
||||
/*
|
||||
* This might get called in the middle of processing another
|
||||
* request on the socket, so we have a spare parameter block for
|
||||
* this purpose (allocating one dynamically would mean having to
|
||||
* free it, which we can't do at interrupt time).
|
||||
*/
|
||||
memcpy(&sock->spareiopb, &sock->iopb, sizeof(TCPiopb));
|
||||
sock->spareiopb.ioCompletion = macnet_closed_upp;
|
||||
sock->spareiopb.csCode = TCPClose;
|
||||
sock->spareiopb.csParam.close.validityFlags = 0;
|
||||
sock->spareiopb.csParam.close.userDataPtr = (char *)sock;
|
||||
err = PBControlAsync((ParmBlkPtr)&sock->spareiopb);
|
||||
switch (err) {
|
||||
case noErr:
|
||||
case connectionClosing:
|
||||
case connectionTerminated: /* We'll get an ASR */
|
||||
break;
|
||||
default:
|
||||
macnet_sendevent(sock, NE_DIED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void macnet_closed(TCPiopb* iopb) {
|
||||
Socket *sock = (Socket *)iopb->csParam.close.userDataPtr;
|
||||
UInt32 olda5;
|
||||
|
||||
olda5 = SetA5(sock->a5);
|
||||
switch (iopb->ioResult) {
|
||||
case noErr:
|
||||
macnet_sendevent(sock, NE_CLOSED);
|
||||
break;
|
||||
case connectionClosing:
|
||||
case connectionTerminated:
|
||||
break;
|
||||
default:
|
||||
macnet_sendevent(sock, NE_DIED);
|
||||
break;
|
||||
}
|
||||
SetA5(olda5);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all the data structures associated with a socket and tear down
|
||||
* any connection through it.
|
||||
*/
|
||||
void net_destroy(Socket *sock) {
|
||||
TCPiopb iopb;
|
||||
OSErr err;
|
||||
|
||||
/*
|
||||
* Yes, we need _another_ iopb, as there may be a send _and_ a
|
||||
* close outstanding. Luckily, destroying a socket is
|
||||
* synchronous, so we can allocate this one dynamically.
|
||||
*/
|
||||
memcpy(&iopb, &sock->iopb, sizeof(TCPiopb));
|
||||
iopb.csCode = TCPRelease;
|
||||
err = PBControlSync((ParmBlkPtr)&iopb);
|
||||
sfree(iopb.csParam.create.rcvBuff);
|
||||
sfree(sock);
|
||||
}
|
||||
|
||||
static void macnet_sendevent(Socket *sock, Net_Event_Type type) {
|
||||
NetEvent *ne;
|
||||
|
||||
ne = (NetEvent *)macnet_freeq.qHead;
|
||||
assert (ne != NULL);
|
||||
Dequeue(&ne->qelem, &macnet_freeq);
|
||||
ne->sock = sock;
|
||||
ne->type = type;
|
||||
Enqueue(&ne->qelem, &macnet_eventq);
|
||||
WakeUpProcess(&sock->psn);
|
||||
}
|
||||
|
||||
/*
|
||||
|
42
macnet.h
42
macnet.h
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* macnet.h -- Mac OS networtking stuff for PuTTY
|
||||
*/
|
||||
|
||||
#ifndef _PUTTY_MACNET_H
|
||||
#define _PUTTY_MACNET_H
|
||||
|
||||
#include <MacTypes.h>
|
||||
#include <AddressXlation.h>
|
||||
#include <MacTCP.h>
|
||||
#include <Processes.h>
|
||||
|
||||
typedef struct {
|
||||
StreamPtr tcp_stream;
|
||||
struct HostInfo host_info;
|
||||
int port;
|
||||
unsigned char *inbuf;
|
||||
int inbuf_head, inbuf_reap, inbuf_size;
|
||||
unsigned char *outbuf;
|
||||
int outbuf_head, outbuf_reap, outbuf_size;
|
||||
ProcessSerialNumber psn;
|
||||
} Socket;
|
||||
|
||||
typedef Socket *SOCKET
|
||||
|
||||
#define INVALID_SOCKET NULL
|
||||
|
||||
#define MSG_OOB 1
|
||||
|
||||
extern int send(SOCKET, const void *, size_t, int);
|
||||
extern int recv(SOCKET, void *, size_t, int);
|
||||
extern SOCKET tcp_open(const char *, int, char **);
|
||||
extern void tcp_close(SOCKET);
|
||||
extern void tcp_abort(SOCKET);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* c-file-style: "simon"
|
||||
* End:
|
||||
*/
|
42
putty.h
42
putty.h
@ -90,18 +90,33 @@ typedef enum {
|
||||
} VT_Mode;
|
||||
|
||||
typedef struct Session Session;
|
||||
typedef struct Socket Socket;
|
||||
|
||||
/* Types of network event */
|
||||
|
||||
typedef enum {
|
||||
NE_NULL, /* Nothing happened */
|
||||
NE_OPEN, /* Connection successfully opened */
|
||||
NE_NOHOST, /* DNS lookup failed for some reason */
|
||||
NE_REFUSED, /* Port unreachable */
|
||||
NE_NOOPEN, /* Connection failed to open for some other reason */
|
||||
NE_DATA, /* Incoming normal data */
|
||||
NE_URGENT, /* Incoming urgent data */
|
||||
NE_CLOSING, /* Connection closed by remote host */
|
||||
NE_CLOSED, /* Connection close completed */
|
||||
NE_TIMEOUT, /* Remote host vanished */
|
||||
NE_ABORT, /* Remote host reset connection */
|
||||
NE_DIED, /* Connection has failed for some other reason */
|
||||
} Net_Event_Type;
|
||||
|
||||
|
||||
typedef struct {
|
||||
#ifdef macintosh
|
||||
char *(*init) (Session *, char *host, int port, char **realhost);
|
||||
int (*msg)(Session *);
|
||||
#else /* not macintosh */
|
||||
char *(*init) (HWND hwnd, char *host, int port, char **realhost);
|
||||
int (*msg) (WPARAM wParam, LPARAM lParam);
|
||||
#endif /* not macintosh */
|
||||
char *(*init) (Session *, char *host, int port);
|
||||
int (*msg)(Session *, Socket *, Net_Event_Type);
|
||||
void (*send) (Session *, char *buf, int len);
|
||||
void (*size) (Session *);
|
||||
void (*special) (Session *, Telnet_Special code);
|
||||
void (*shutdown) (Session *);
|
||||
} Backend;
|
||||
|
||||
typedef struct {
|
||||
@ -252,6 +267,7 @@ typedef struct Session {
|
||||
#endif
|
||||
} Session;
|
||||
|
||||
typedef struct Socket Socket;
|
||||
|
||||
/*
|
||||
* Exports from display system
|
||||
@ -273,7 +289,17 @@ void fatalbox (const char *, ...);
|
||||
#pragma noreturn (fatalbox)
|
||||
#endif
|
||||
extern void beep (Session *s);
|
||||
#define OPTIMISE_IS_SCROLL 1
|
||||
|
||||
/*
|
||||
* Exports from the network system
|
||||
*/
|
||||
|
||||
extern Socket *net_open(Session *, char *host, int port);
|
||||
extern char *net_realname(Socket *);
|
||||
extern int net_recv(Socket *, void *, int, int);
|
||||
extern int net_send(Socket *, void *, int, int);
|
||||
extern void net_close(Socket *); /* ask the remote end to close */
|
||||
extern void net_destroy(Socket *); /* Tidy up */
|
||||
|
||||
/*
|
||||
* Exports from noise.c.
|
||||
|
Loading…
Reference in New Issue
Block a user