472 lines
12 KiB
C++
472 lines
12 KiB
C++
/*********************************************************************
|
|
Project : GUSI - Grand Unified Socket Interface
|
|
File : GUSI_P.h - Private stuff
|
|
Author : Matthias Neeracher
|
|
Language : MPW C/C++
|
|
|
|
$Log$
|
|
Revision 1.1 1998/08/18 14:52:33 jack
|
|
Putting Python-specific GUSI modifications under CVS.
|
|
|
|
Revision 1.3 1994/12/31 01:30:26 neeri
|
|
Reorganize filename dispatching.
|
|
|
|
Revision 1.2 1994/08/10 00:41:05 neeri
|
|
Sanitized for universal headers.
|
|
|
|
Revision 1.1 1994/02/25 02:57:01 neeri
|
|
Initial revision
|
|
|
|
Revision 0.22 1993/07/17 00:00:00 neeri
|
|
GUSIRingBuffer::proc -> defproc
|
|
|
|
Revision 0.21 1993/07/17 00:00:00 neeri
|
|
GUSIO_MAX_DOMAIN -> AF_MAX
|
|
|
|
Revision 0.20 1993/06/27 00:00:00 neeri
|
|
Socket::{pre,post}_select
|
|
|
|
Revision 0.19 1993/06/27 00:00:00 neeri
|
|
Socket::ftruncate
|
|
|
|
Revision 0.18 1993/02/09 00:00:00 neeri
|
|
Socket::lurking, Socket::lurkdescr
|
|
|
|
Revision 0.17 1993/01/31 00:00:00 neeri
|
|
GUSIConfiguration::daemon
|
|
|
|
Revision 0.16 1993/01/17 00:00:00 neeri
|
|
Destructors for Socketdomain
|
|
|
|
Revision 0.15 1993/01/17 00:00:00 neeri
|
|
SAFESPIN
|
|
|
|
Revision 0.14 1993/01/03 00:00:00 neeri
|
|
GUSIConfig
|
|
|
|
Revision 0.13 1992/09/24 00:00:00 neeri
|
|
Include GUSIRsrc_P.h
|
|
|
|
Revision 0.12 1992/09/13 00:00:00 neeri
|
|
SPINVOID didn't return
|
|
|
|
Revision 0.11 1992/08/30 00:00:00 neeri
|
|
AppleTalkIdentity()
|
|
|
|
Revision 0.10 1992/08/03 00:00:00 neeri
|
|
RingBuffer
|
|
|
|
Revision 0.9 1992/07/30 00:00:00 neeri
|
|
Initializer Features
|
|
|
|
Revision 0.8 1992/07/26 00:00:00 neeri
|
|
UnixSockets.choose()
|
|
|
|
Revision 0.7 1992/07/13 00:00:00 neeri
|
|
Make AppleTalkSockets global
|
|
|
|
Revision 0.6 1992/06/27 00:00:00 neeri
|
|
choose(), hasNewSF
|
|
|
|
Revision 0.5 1992/06/07 00:00:00 neeri
|
|
Feature
|
|
|
|
Revision 0.4 1992/05/21 00:00:00 neeri
|
|
Implemented select()
|
|
|
|
Revision 0.3 1992/04/19 00:00:00 neeri
|
|
C++ rewrite
|
|
|
|
Revision 0.2 1992/04/18 00:00:00 neeri
|
|
changed read/write/send/recv dispatchers
|
|
|
|
Revision 0.1 1992/04/18 00:00:00 neeri
|
|
ppc Domain
|
|
|
|
*********************************************************************/
|
|
|
|
#ifndef __GUSI_P__
|
|
#define __GUSI_P__
|
|
|
|
#define __useAppleExts__
|
|
|
|
#include <GUSI.h>
|
|
#include <GUSIRsrc_P.h>
|
|
#include <TFileSpec.h>
|
|
|
|
|
|
#include <sys/errno.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/socket.h>
|
|
|
|
extern "C" {
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
int GUSI_error(int err);
|
|
void * GUSI_error_nil(int err);
|
|
}
|
|
|
|
#include <Memory.h>
|
|
#include <Gestalt.h>
|
|
#include <Traps.h>
|
|
#include <AppleEvents.h>
|
|
#include <Processes.h>
|
|
#include <MixedMode.h>
|
|
|
|
#if MSLGUSI
|
|
using namespace std;
|
|
#endif
|
|
|
|
#if GENERATING68K
|
|
#pragma segment GUSI
|
|
#endif
|
|
|
|
#define GUSI_MAX_DOMAIN AF_MAX
|
|
#define DEFAULT_BUFFER_SIZE 4096
|
|
|
|
/*
|
|
* In use and shutdown status.
|
|
*/
|
|
#define SOCK_STATUS_USED 0x1 /* Used socket table entry */
|
|
#define SOCK_STATUS_NOREAD 0x2 /* No more reading allowed from socket */
|
|
#define SOCK_STATUS_NOWRITE 0x4 /* No more writing allowed to socket */
|
|
|
|
/*
|
|
* Socket connection states.
|
|
*/
|
|
#define SOCK_STATE_NO_STREAM 0 /* Socket doesn't have a MacTCP stream yet */
|
|
#define SOCK_STATE_UNCONNECTED 1 /* Socket is unconnected. */
|
|
#define SOCK_STATE_LISTENING 2 /* Socket is listening for connection. */
|
|
#define SOCK_STATE_LIS_CON 3 /* Socket is in transition from listen to connected. */
|
|
#define SOCK_STATE_CONNECTING 4 /* Socket is initiating a connection. */
|
|
#define SOCK_STATE_CONNECTED 5 /* Socket is connected. */
|
|
#define SOCK_STATE_CLOSING 6 /* Socket is closing */
|
|
#define SOCK_STATE_LIS_CLOSE 7 /* Socket closed while listening */
|
|
|
|
#define min(a,b) ( (a) < (b) ? (a) : (b))
|
|
#define max(a,b) ( (a) > (b) ? (a) : (b))
|
|
|
|
extern GUSISpinFn GUSISpin;
|
|
extern "C" int GUSIDefaultSpin(spin_msg, long);
|
|
extern int GUSICheckAlarm();
|
|
|
|
#define GUSI_INTERRUPT(mesg,param) (GUSICheckAlarm() || (GUSISpin && (*GUSISpin)(mesg,param)))
|
|
|
|
/* SPIN returns a -1 on user cancel for fn returning integers */
|
|
#define SPIN(cond,mesg,param) \
|
|
do { \
|
|
if (GUSI_INTERRUPT(mesg,param)) \
|
|
return GUSI_error(EINTR); \
|
|
} while(cond)
|
|
|
|
/* SPINP returns a NULL on user cancel, for fn returning pointers */
|
|
#define SPINP(cond,mesg,param) \
|
|
do { \
|
|
if (GUSI_INTERRUPT(mesg,param)) { \
|
|
GUSI_error(EINTR); \
|
|
return NULL; \
|
|
} \
|
|
} while(cond)
|
|
|
|
/* SPINVOID just returns on user cancel, for fn returning void */
|
|
#define SPINVOID(cond,mesg,param) \
|
|
do { \
|
|
if (GUSI_INTERRUPT(mesg,param)) { \
|
|
GUSI_error(EINTR); \
|
|
return; \
|
|
} \
|
|
} while(cond)
|
|
|
|
/* SAFESPIN doesn't return, you have to check errno */
|
|
#define SAFESPIN(cond,mesg,param) \
|
|
do { \
|
|
if (GUSI_INTERRUPT(mesg,param)) { \
|
|
GUSI_error(EINTR); \
|
|
break; \
|
|
} else \
|
|
errno = 0; \
|
|
} while(cond)
|
|
|
|
//
|
|
// Library functions are never allowed to clear errno, so we have to save
|
|
//
|
|
class ErrnoSaver {
|
|
public:
|
|
ErrnoSaver() { fSavedErrno = ::errno; ::errno = 0; }
|
|
~ErrnoSaver() { if (!::errno) ::errno = fSavedErrno; }
|
|
private:
|
|
int fSavedErrno;
|
|
};
|
|
|
|
#define SAVE_AND_CLEAR_ERRNO ErrnoSaver saveErrno
|
|
|
|
class SocketTable;
|
|
|
|
#if PRAGMA_ALIGN_SUPPORTED
|
|
#pragma options align=mac68k
|
|
#endif
|
|
|
|
class Socket {
|
|
friend class SocketTable;
|
|
|
|
short refCount;
|
|
protected:
|
|
Socket();
|
|
public:
|
|
virtual int bind(void * name, int namelen);
|
|
virtual int connect(void * address, int addrlen);
|
|
virtual int listen(int qlen);
|
|
virtual Socket * accept(void * address, int * addrlen);
|
|
virtual int read(void * buffer, int buflen);
|
|
virtual int write(void * buffer, int buflen);
|
|
virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
|
|
virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
|
|
virtual int getsockname(void * name, int * namelen);
|
|
virtual int getpeername(void * name, int * namelen);
|
|
virtual int getsockopt(int level, int optname, void *optval, int * optlen);
|
|
virtual int setsockopt(int level, int optname, void *optval, int optlen);
|
|
virtual int fcntl(unsigned int cmd, int arg);
|
|
virtual int ioctl(unsigned int request, void *argp);
|
|
virtual int fstat(struct stat * buf);
|
|
virtual long lseek(long offset, int whence);
|
|
virtual int ftruncate(long offset);
|
|
virtual int isatty();
|
|
virtual int shutdown(int how);
|
|
virtual void pre_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
|
|
virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
|
|
virtual void post_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
|
|
virtual ~Socket();
|
|
|
|
void operator++() { ++refCount; }
|
|
void operator--() { if (!--refCount) delete this; }
|
|
};
|
|
|
|
|
|
#if PRAGMA_ALIGN_SUPPORTED
|
|
#pragma options align=reset
|
|
#endif
|
|
|
|
class SocketDomain {
|
|
static SocketDomain * domains[GUSI_MAX_DOMAIN];
|
|
static ProcessSerialNumber process;
|
|
protected:
|
|
SocketDomain(int domain);
|
|
virtual ~SocketDomain();
|
|
public:
|
|
inline static SocketDomain * Domain(int domain);
|
|
static void Ready();
|
|
|
|
// Optionally override the following
|
|
|
|
virtual Socket * socket(int type, short protocol);
|
|
|
|
// Optionally override the following
|
|
|
|
virtual int socketpair(int type, short protocol, Socket * sockets[]);
|
|
|
|
// Optionally define the following
|
|
|
|
virtual int choose(
|
|
int type,
|
|
char * prompt,
|
|
void * constraint,
|
|
int flags,
|
|
void * name,
|
|
int * namelen);
|
|
|
|
// Never override the following
|
|
|
|
void DontStrip();
|
|
};
|
|
|
|
class SocketTable {
|
|
Socket * sockets[GUSI_MAX_FD];
|
|
Boolean needsConsole;
|
|
public:
|
|
SocketTable();
|
|
~SocketTable();
|
|
|
|
void InitConsole();
|
|
int Install(Socket * sock, int start = 0);
|
|
int Remove(int fd);
|
|
Socket * operator[](int fd);
|
|
};
|
|
|
|
struct GUSISuffix {
|
|
char suffix[4];
|
|
OSType suffType;
|
|
OSType suffCreator;
|
|
};
|
|
|
|
#if PRAGMA_ALIGN_SUPPORTED
|
|
#pragma options align=mac68k
|
|
#endif
|
|
|
|
//
|
|
// I learned the hard way not to rely on bit field alignments
|
|
//
|
|
|
|
struct GUSIConfigRsrc {
|
|
OSType defaultType;
|
|
OSType defaultCreator;
|
|
|
|
char autoSpin;
|
|
unsigned char flags;
|
|
|
|
OSType version;
|
|
short numSuffices;
|
|
GUSISuffix suffices[1];
|
|
};
|
|
|
|
#if PRAGMA_ALIGN_SUPPORTED
|
|
#pragma options align=reset
|
|
#endif
|
|
|
|
struct GUSIConfiguration {
|
|
OSType defaultType;
|
|
OSType defaultCreator;
|
|
|
|
char autoSpin;
|
|
|
|
Boolean noChdir; // Set current directory without chdir()
|
|
Boolean accurStat; // Return # of subdirectories + 2 in st_nlink
|
|
Boolean hasConsole; // Do we have our own console ?
|
|
Boolean noAutoInitGraf; // Never automatically do InitGraf
|
|
Boolean sharedOpen; // Open files with shared permissions
|
|
Boolean sigPipe; // raise SIGPIPE on write to closed socket
|
|
Boolean noAppleEvents; // Don't solicit AppleEvents for MPW tools
|
|
Boolean delayConsole; // Do not open console until needed
|
|
|
|
OSType version;
|
|
short numSuffices;
|
|
GUSISuffix * suffices;
|
|
|
|
GUSIConfiguration();
|
|
void GUSILoadConfiguration(Handle config);
|
|
|
|
void SetDefaultFType(const TFileSpec & name) const;
|
|
void DoAutoSpin() const;
|
|
void AutoInitGraf() const { if (!noAutoInitGraf) DoAutoInitGraf(); }
|
|
void DoAutoInitGraf() const;
|
|
Boolean DelayConsole() const;
|
|
private:
|
|
static Boolean firstTime;
|
|
static short we;
|
|
};
|
|
|
|
extern GUSIConfiguration GUSIConfig;
|
|
extern SocketTable Sockets;
|
|
|
|
typedef pascal OSErr (*OSErrInitializer)();
|
|
typedef pascal void (*voidInitializer)();
|
|
|
|
class Feature {
|
|
Boolean good;
|
|
public:
|
|
Feature(unsigned short trapNum, TrapType tTyp);
|
|
Feature(OSType type, long value);
|
|
Feature(OSType type, long mask, long value);
|
|
Feature(const Feature & precondition, OSErrInitializer init);
|
|
Feature(OSErrInitializer init);
|
|
Feature(const Feature & precondition, voidInitializer init);
|
|
Feature(voidInitializer init);
|
|
Feature(const Feature & cond1, const Feature & cond2);
|
|
|
|
operator void*() const { return (void *) good; }
|
|
};
|
|
|
|
extern Feature hasMakeFSSpec;
|
|
extern Feature hasAlias;
|
|
extern Feature hasNewSF;
|
|
extern Feature hasProcessMgr;
|
|
extern Feature hasCRM;
|
|
extern Feature hasCTB;
|
|
extern Feature hasStdNBP;
|
|
extern Feature hasCM;
|
|
extern Feature hasFT;
|
|
extern Feature hasTM;
|
|
extern Feature hasPPC;
|
|
extern Feature hasRevisedTimeMgr;
|
|
|
|
class ScattGath {
|
|
Handle scratch;
|
|
protected:
|
|
void * buf;
|
|
int len;
|
|
int count;
|
|
const struct iovec * io;
|
|
|
|
ScattGath(const struct iovec *iov, int cnt);
|
|
virtual ~ScattGath();
|
|
public:
|
|
void * buffer() { return buf; }
|
|
int buflen() { return len; }
|
|
int length(int l) { return len = l; }
|
|
operator void *() { return buf; }
|
|
};
|
|
|
|
class Scatterer : public ScattGath {
|
|
public:
|
|
Scatterer(const struct iovec *iov, int count);
|
|
virtual ~Scatterer();
|
|
};
|
|
|
|
class Gatherer : public ScattGath {
|
|
public:
|
|
Gatherer(const struct iovec *iov, int count);
|
|
virtual ~Gatherer();
|
|
};
|
|
|
|
typedef pascal void (*Deferred)(void *);
|
|
|
|
class RingBuffer {
|
|
// Valid bytes are between consume and produce
|
|
// Free bytes are between produce and consume
|
|
// bytes between endbuf-spare and endbuf are neither
|
|
Ptr buffer;
|
|
Ptr endbuf;
|
|
Ptr consume;
|
|
Ptr produce;
|
|
u_short free;
|
|
u_short valid;
|
|
u_short spare;
|
|
Boolean lock;
|
|
Deferred defproc;
|
|
void * arg;
|
|
|
|
public:
|
|
RingBuffer(u_short bufsiz);
|
|
~RingBuffer();
|
|
|
|
Ptr Producer(long & len); // Find continuous memory for producer
|
|
Ptr Consumer(long & len); // Find continuous memory for consumer
|
|
void Validate(long len); // Validate this, unallocate rest
|
|
void Invalidate(long len);
|
|
void Produce(Ptr from, long & len);// Allocate, copy & validate
|
|
void Consume(Ptr to, long & len); // Copy & invalidate
|
|
|
|
long Free() { return free; }
|
|
long Valid() { return valid; }
|
|
|
|
void Defer() { lock = true; }
|
|
void Undefer() { lock = false; if (defproc) defproc(arg);}
|
|
Boolean Locked() { return lock; }
|
|
void Later(Deferred def, void * ar){ defproc = def; arg = ar; }
|
|
|
|
operator void *() { return buffer; }
|
|
};
|
|
|
|
Boolean GUSIInterrupt();
|
|
|
|
Boolean CopyIconFamily(short srcResFile, short srcID, short dstResFile, short dstID);
|
|
|
|
pascal OSErr PPCInit_P();
|
|
|
|
OSErr AppleTalkIdentity(short & net, short & node);
|
|
|
|
void CopyC2PStr(const char * cstr, StringPtr pstr);
|
|
|
|
#endif
|