blob: 66ee3a76c80798426beff35b5e1d1c62a87f5f1b [file] [log] [blame]
/*********************************************************************
Project : GUSI - Grand Unified Socket Interface
File : GUSI_P.h - Private stuff
Author : Matthias Neeracher
Language : MPW C/C++
$Log$
Revision 1.1 2000/09/12 20:24:46 jack
Moved to Unsupported.
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