diff options
author | Jack Jansen <jack.jansen@cwi.nl> | 1998-08-18 14:52:38 (GMT) |
---|---|---|
committer | Jack Jansen <jack.jansen@cwi.nl> | 1998-08-18 14:52:38 (GMT) |
commit | 1d6a6ea1a819a645a3a8841205b10cf33eb04493 (patch) | |
tree | 464997cdd49781964e5928be1a5d99311b24c3ec /Mac | |
parent | b0195ec9c136300bcd65d89bfdf287a98af6c7de (diff) | |
download | cpython-1d6a6ea1a819a645a3a8841205b10cf33eb04493.zip cpython-1d6a6ea1a819a645a3a8841205b10cf33eb04493.tar.gz cpython-1d6a6ea1a819a645a3a8841205b10cf33eb04493.tar.bz2 |
Putting Python-specific GUSI modifications under CVS.
Diffstat (limited to 'Mac')
-rw-r--r-- | Mac/GUSI-mods/into-include/GUSI.h | 366 | ||||
-rw-r--r-- | Mac/GUSI-mods/into-include/GUSI_P.h | 471 | ||||
-rw-r--r-- | Mac/GUSI-mods/into-src/GUSI.r | 168 | ||||
-rw-r--r-- | Mac/GUSI-mods/into-src/GUSIDispatch.cp | 1434 | ||||
-rw-r--r-- | Mac/GUSI-mods/into-src/GUSINetDB.cp | 579 | ||||
-rw-r--r-- | Mac/GUSI-mods/into-src/GUSISIOUX.cp | 246 |
6 files changed, 3264 insertions, 0 deletions
diff --git a/Mac/GUSI-mods/into-include/GUSI.h b/Mac/GUSI-mods/into-include/GUSI.h new file mode 100644 index 0000000..07ce429 --- /dev/null +++ b/Mac/GUSI-mods/into-include/GUSI.h @@ -0,0 +1,366 @@ +/********************************************************************* +Project : GUSI - Grand Unified Socket Interface +File : GUSI.h - Socket calls +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.2 1994/12/31 01:45:54 neeri +Fix alignment. + +Revision 1.1 1994/02/25 02:56:49 neeri +Initial revision + +Revision 0.15 1993/06/27 00:00:00 neeri +f?truncate + +Revision 0.14 1993/06/20 00:00:00 neeri +Changed sa_constr_ppc + +Revision 0.13 1993/02/14 00:00:00 neeri +AF_PAP + +Revision 0.12 1992/12/08 00:00:00 neeri +getcwd() + +Revision 0.11 1992/11/15 00:00:00 neeri +remove netdb.h definitions + +Revision 0.10 1992/09/26 00:00:00 neeri +Separate dirent and stat + +Revision 0.9 1992/09/12 00:00:00 neeri +Hostname stuff + +Revision 0.8 1992/09/07 00:00:00 neeri +readlink() + +Revision 0.7 1992/08/03 00:00:00 neeri +sa_constr_ppc + +Revision 0.6 1992/07/21 00:00:00 neeri +sockaddr_atlk_sym + +Revision 0.5 1992/06/26 00:00:00 neeri +choose() + +Revision 0.4 1992/05/18 00:00:00 neeri +PPC stuff + +Revision 0.3 1992/04/27 00:00:00 neeri +getsockopt() + +Revision 0.2 1992/04/19 00:00:00 neeri +C++ compatibility + +Revision 0.1 1992/04/17 00:00:00 neeri +bzero() + +*********************************************************************/ + +#ifndef _GUSI_ +#define _GUSI_ + +#include <sys/types.h> + +/* Feel free to increase FD_SETSIZE as needed */ +#define GUSI_MAX_FD FD_SETSIZE + +#include <sys/cdefs.h> +#include <compat.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <dirent.h> +#include <Types.h> +#include <Events.h> +#include <Files.h> +#include <AppleTalk.h> +#include <CTBUtilities.h> +#include <Packages.h> +#include <PPCToolBox.h> +#include <StandardFile.h> +#include <stdio.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <string.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/un.h> +#include <unistd.h> +#include <machine/endian.h> + +typedef enum spin_msg { + SP_MISC, /* some weird thing, usually just return immediately if you get this */ + SP_SELECT, /* in a select call */ + SP_NAME, /* getting a host by name */ + SP_ADDR, /* getting a host by address */ + SP_STREAM_READ, /* Stream read call */ + SP_STREAM_WRITE, /* Stream write call */ + SP_DGRAM_READ, /* Datagram read call */ + SP_DGRAM_WRITE, /* Datagram write call */ + SP_SLEEP, /* sleeping, passes ticks left to sleep */ + SP_AUTO_SPIN /* Autospin, passes argument to SpinCursor */ +} spin_msg; + +typedef int (*GUSISpinFn)(spin_msg msg, long param); +typedef void (*GUSIEvtHandler)(EventRecord * ev); +typedef GUSIEvtHandler GUSIEvtTable[24]; + +/* + * Address families, defined in sys/socket.h + * + +#define AF_UNSPEC 0 // unspecified +#define AF_UNIX 1 // local to host (pipes, portals) +#define AF_INET 2 // internetwork: UDP, TCP, etc. +#define AF_CTB 3 // Apple Comm Toolbox (not yet supported) +#define AF_FILE 4 // Normal File I/O (used internally) +#define AF_PPC 5 // PPC Toolbox +#define AF_PAP 6 // Printer Access Protocol (client only) +#define AF_APPLETALK 16 // Apple Talk + +*/ + +#define ATALK_SYMADDR 272 /* Symbolic Address for AppleTalk */ + +/* + * Some Implementations of GUSI require you to call GUSISetup for the + * socket families you'd like to have defined. It's a good idea to call + * this for *all* implementations. + * + * GUSIDefaultSetup() will include all socket families. + * + * Never call any of the GUSIwithXXX routines directly. + */ + +__BEGIN_DECLS +void GUSIwithAppleTalkSockets(); +void GUSIwithInternetSockets(); +void GUSIwithPAPSockets(); +void GUSIwithPPCSockets(); +void GUSIwithUnixSockets(); +void GUSIwithSIOUXSockets(); +void GUSIwithMPWSockets(); + +void GUSISetup(void (*socketfamily)()); +void GUSIDefaultSetup(); +void GUSILoadConfiguration(Handle); +__END_DECLS +/* + * Types, defined in sys/socket.h + * + +#define SOCK_STREAM 1 // stream socket +#define SOCK_DGRAM 2 // datagram socket + +*/ + +/* + * Defined in sys/un.h + * + +struct sockaddr_un { + short sun_family; + char sun_path[108]; +}; + +*/ + +#ifndef PRAGMA_ALIGN_SUPPORTED +#error Apple had some fun with the conditional macros again +#endif + +#if PRAGMA_ALIGN_SUPPORTED +#pragma options align=mac68k +#endif + +struct sockaddr_atlk { + short family; + AddrBlock addr; +}; + +struct sockaddr_atlk_sym { + short family; + EntityName name; +}; + +struct sockaddr_ppc { + short family; + LocationNameRec location; + PPCPortRec port; +}; + +/* Definitions for choose() */ + +#define CHOOSE_DEFAULT 1 /* Use *name as default name */ +#define CHOOSE_NEW 2 /* Choose new entity name, not existing one */ +#define CHOOSE_DIR 4 /* Choose a directory name, not a file */ + +typedef struct { + short numTypes; + SFTypeList types; +} sa_constr_file; + +typedef struct { + short numTypes; + NLType types; +} sa_constr_atlk; + +/* Definitions for sa_constr_ppc */ + +#define PPC_CON_NEWSTYLE 0x8000 /* Required */ +#define PPC_CON_MATCH_NAME 0x0001 /* Match name */ +#define PPC_CON_MATCH_TYPE 0x0002 /* Match port type */ +#define PPC_CON_MATCH_NBP 0x0004 /* Match NBP type */ + +typedef struct { + short flags; + Str32 nbpType; + PPCPortRec match; +} sa_constr_ppc; + +#if PRAGMA_ALIGN_SUPPORTED +#pragma options align=reset +#endif + +__BEGIN_DECLS +/* + * IO/Socket stuff, defined elsewhere (unistd.h, sys/socket.h + * + +int socket(int domain, int type, short protocol); +int bind(int s, void *name, int namelen); +int connect(int s, void *addr, int addrlen); +int listen(int s, int qlen); +int accept(int s, void *addr, int *addrlen); +int close(int s); +int read(int s, char *buffer, unsigned buflen); +int readv(int s, struct iovec *iov, int count); +int recv(int s, void *buffer, int buflen, int flags); +int recvfrom(int s, void *buffer, int buflen, int flags, void *from, int *fromlen); +int recvmsg(int s,struct msghdr *msg,int flags); +int write(int s, const char *buffer, unsigned buflen); +int writev(int s, struct iovec *iov, int count); +int send(int s, void *buffer, int buflen, int flags); +int sendto (int s, void *buffer, int buflen, int flags, void *to, int tolen); +int sendmsg(int s,struct msghdr *msg,int flags); +int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); +int getdtablesize(void); +int getsockname(int s, void *name, int *namelen); +int getpeername(int s, struct sockaddr *name, int *namelen); +int shutdown(int s, int how); +int fcntl(int s, unsigned int cmd, int arg); +int dup(int s); +int dup2(int s, int s1); +int ioctl(int d, unsigned int request, long *argp); +int getsockopt(int s, int level, int optname, char *optval, int * optlen); +int setsockopt(int s, int level, int optname, char *optval, int optlen); +int isatty(int); +int remove(const char *filename); +int rename(const char *oldname, const char *newname); +int creat(const char*); +int faccess(char*, unsigned int, long*); +long lseek(int, long, int); +int open(const char*, int); +int unlink(char*); +int symlink(char* linkto, char* linkname); +int readlink(char* path, char* buf, int bufsiz); +int truncate(char *path, long length); +int ftruncate(int fd, long length); +int chdir(char * path); +int mkdir(char * path); +int rmdir(char * path); +char * getcwd(char * buf, int size); +*/ + +/* + * Defined in stdio.h + */ + +#ifdef __MWERKS__ +void fsetfileinfo (char *filename, unsigned long newcreator, unsigned long newtype); +#endif + +void fgetfileinfo (char *filename, unsigned long * creator, unsigned long * type); + +#ifdef __MWERKS__ +FILE *fdopen(int fd, const char *mode); +int fwalk(int (*func)(FILE * stream)); +#endif + +int choose( + int domain, + int type, + char * prompt, + void * constraint, + int flags, + void * name, + int * namelen); + +/* + * Hostname routines, defined in netdb.h + * + +struct hostent * gethostbyname(char *name); +struct hostent * gethostbyaddr(struct in_addr *addrP, int, int); +int gethostname(char *machname, long buflen); +struct servent * getservbyname (char * name, char * proto); +struct protoent * getprotobyname(char * name); + +*/ + +char * inet_ntoa(struct in_addr inaddr); +struct in_addr inet_addr(char *address); + +/* + * GUSI supports a number of hooks. Every one of them has a different prototype, but needs + * to be passed as a GUSIHook + */ + +typedef enum { + GUSI_SpinHook, /* A GUSISpinFn, to be called when a call blocks */ + GUSI_ExecHook, /* Boolean (*hook)(const GUSIFileRef & ref), decides if file is executable */ + GUSI_FTypeHook,/* Boolean (*hook)(const FSSpec & spec) sets a default file type */ + GUSI_SpeedHook /* A long integer, to be added to the cursor spin variable */ +} GUSIHookCode; + +typedef void (*GUSIHook)(void); +void GUSISetHook(GUSIHookCode code, GUSIHook hook); +GUSIHook GUSIGetHook(GUSIHookCode code); + +/* + * What to do when a routine blocks + */ + +/* Defined for compatibility */ +#define GUSISetSpin(routine) GUSISetHook(GUSI_SpinHook, (GUSIHook)routine) +#define GUSIGetSpin() (GUSISpinFn) GUSIGetHook(GUSI_SpinHook) + +int GUSISetEvents(GUSIEvtTable table); +GUSIEvtHandler * GUSIGetEvents(void); + +extern GUSIEvtHandler GUSISIOWEvents[]; + +#define SIGPIPE 13 +#define SIGALRM 14 + +/* + * BSD memory routines, defined in compat.h + * + +#define index(a, b) strchr(a, b) +#define rindex(a, b) strrchr(a, b) +#define bzero(from, len) memset(from, 0, len) +#define bcopy(from, to, len) memcpy(to, from, len) +#define bcmp(s1, s2, len) memcmp(s1, s2, len) +#define bfill(from, len, x) memset(from, x, len) + + */ + +__END_DECLS + +#endif /* !_GUSI_ */ diff --git a/Mac/GUSI-mods/into-include/GUSI_P.h b/Mac/GUSI-mods/into-include/GUSI_P.h new file mode 100644 index 0000000..1bc5523 --- /dev/null +++ b/Mac/GUSI-mods/into-include/GUSI_P.h @@ -0,0 +1,471 @@ +/********************************************************************* +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 diff --git a/Mac/GUSI-mods/into-src/GUSI.r b/Mac/GUSI-mods/into-src/GUSI.r new file mode 100644 index 0000000..6da7fd6 --- /dev/null +++ b/Mac/GUSI-mods/into-src/GUSI.r @@ -0,0 +1,168 @@ +/********************************************************************* +Project : GUSI - Grand Unified Socket Interface +File : GUSI.r - Include this +Author : Matthias Neeracher +Language : MPW Rez 3.0 + +$Log$ +Revision 1.1 1998/08/18 14:52:37 jack +Putting Python-specific GUSI modifications under CVS. + +Revision 1.3 1994/12/30 19:33:34 neeri +Enlargened message box for select folder dialog. + +Revision 1.2 1994/08/10 00:34:18 neeri +Sanitized for universal headers. + +Revision 1.1 1994/02/25 02:12:04 neeri +Initial revision + +Revision 0.5 1993/05/21 00:00:00 neeri +suffixes + +Revision 0.4 1993/01/31 00:00:00 neeri +Daemon + +Revision 0.3 1993/01/03 00:00:00 neeri +autoSpin + +Revision 0.2 1992/09/24 00:00:00 neeri +Don't include CKID, create GUSIRsrc_P.h + +Revision 0.1 1992/07/13 00:00:00 neeri +.rsrc + +*********************************************************************/ + +#include "Types.r" +#include "GUSIRsrc_P.h" + +include "GUSI.rsrc" not 'ckid'; + +/* Define a resource ('GU…I', GUSIRsrcID) to override GUSI defaults + To avoid having to change the Rez file every time I introduce another + feature, the preprocessor variable GUSI_PREF_VERSION by default keeps + everything compatible with version 1.0.2. Just define GUSI_PREF_VERSION + to be the version you want to use. +*/ + +#ifndef GUSI_PREF_VERSION +#define GUSI_PREF_VERSION '0102' +#endif + +type 'GU…I' { + literal longint text = 'TEXT'; /* Type for creat'ed files */ + literal longint mpw = 'MPS '; /* Creator for creat'ed files */ + byte noAutoSpin, autoSpin; /* Automatically spin cursor ? */ +#if GUSI_PREF_VERSION > '0102' + boolean useChdir, dontUseChdir; /* Use chdir() ? */ + boolean approxStat, accurateStat; /* statbuf.st_nlink = # of subdirectories ? */ +#if GUSI_PREF_VERSION >= '0181' + boolean noDelayConsole, DelayConsole; /* Delay opening console window until needed? */ + fill bit[1]; +#else + boolean noTCPDaemon, isTCPDaemon; /* Inetd client ? */ + boolean noUDPDaemon, isUDPDaemon; +#endif +#if GUSI_PREF_VERSION >= '0150' +#if GUSI_PREF_VERSION >= '0181' + boolean wantAppleEvents, noAppleEvents; /* Always solicit AppleEvents */ +#else + boolean noConsole, hasConsole; /* Are we providing our own dev:console ? (Obsolete) */ +#endif +#if GUSI_PREF_VERSION >= '0180' + boolean autoInitGraf, noAutoInitGraf; /* Automatically do InitGraf ? */ + boolean exclusiveOpen, sharedOpen; /* Shared open() ? */ + boolean noSigPipe, sigPipe; /* raise SIGPIPE on write to closed PIPE */ +#else + fill bit[3]; +#endif +#else + fill bit[4]; +#endif + literal longint = GUSI_PREF_VERSION; +#if GUSI_PREF_VERSION >= '0120' + integer = $$Countof(SuffixArray); + wide array SuffixArray { + literal longint; /* Suffix of file */ + literal longint; /* Type for file */ + literal longint; /* Creator for file */ + }; +#endif +#endif +}; + +type 'TMPL' { + wide array { + pstring; + literal longint; + }; +}; + +resource 'TMPL' (GUSIRsrcID, "GU…I") { + { + "Type of created files", 'TNAM', + "Creator of created files", 'TNAM', + "Automatically spin cursor", 'DBYT', +#if GUSI_PREF_VERSION > '0102' + "Not using chdir()", 'BBIT', + "Accurate stat()", 'BBIT', + "TCP daemon", 'BBIT', + "UDP daemon", 'BBIT', +#if GUSI_PREF_VERSION >= '0150' + "Own Console", 'BBIT', +#else + "Reserved", 'BBIT', +#endif +#if GUSI_PREF_VERSION >= '0180' + "Don't initialize QuickDraw", 'BBIT', + "Open files shared", 'BBIT', + "Raise SIGPIPE", 'BBIT', +#else + "Reserved", 'BBIT', + "Reserved", 'BBIT', + "Reserved", 'BBIT', +#endif + "Version (don't change)", 'TNAM', +#if GUSI_PREF_VERSION >= '0120' + "NumSuffices", 'OCNT', + "*****", 'LSTC', + "Suffix", 'TNAM', + "Type for suffix", 'TNAM', + "Creator for suffix", 'TNAM', + "*****", 'LSTE', +#endif +#endif + } +}; + +resource 'DLOG' (GUSIRsrcID, "Get Directory") { + {0, 0, 217, 348}, + dBoxProc, + invisible, + noGoAway, + 0x0, + 10240, + "", + alertPositionMainScreen +}; + +resource 'DITL' (GUSIRsrcID, "Get Directory") { + { + { 142, 256, 160, 336}, Button {enabled,"Open"}, + {1152, 59, 1232, 77}, Button {enabled,"Hidden"}, + { 193, 256, 211, 336}, Button {enabled,"Cancel"}, + { 43, 232, 63, 347}, UserItem {disabled}, + { 72, 256, 90, 336}, Button {enabled,"Eject"}, + { 97, 256, 115, 336}, Button {enabled,"Drive"}, + { 43, 12, 189, 230}, UserItem {enabled}, + { 43, 229, 189, 246}, UserItem {enabled}, + { 128, 252, 129, 340}, UserItem {disabled}, + {1044, 20, 1145, 116}, StaticText {disabled,""}, + { 167, 256, 185, 336}, Button {enabled,"Directory"}, + { 0, 30, 18, 215}, Button {enabled,"Select Current Directory:"}, + { 200, 20, 1145, 222}, StaticText {disabled,"Select a Folder"} + } +}; + + diff --git a/Mac/GUSI-mods/into-src/GUSIDispatch.cp b/Mac/GUSI-mods/into-src/GUSIDispatch.cp new file mode 100644 index 0000000..86941cb --- /dev/null +++ b/Mac/GUSI-mods/into-src/GUSIDispatch.cp @@ -0,0 +1,1434 @@ +/********************************************************************* +Project : GUSI - Grand Unified Socket Interface +File : GUSIDispatch.cp- Dispatch calls to their correct recipient +Author : Matthias Neeracher +Language: MPW C/C++ + +$Log$ +Revision 1.1 1998/08/18 14:52:37 jack +Putting Python-specific GUSI modifications under CVS. + +Revision 1.4 1994/12/30 19:48:09 neeri +Remove (theoretical) support for pre-System 6 systems. +Remove built-in support for INETd. +Fix problems in connection with ROM PowerPC library. +Move open() to GUSIFileDispatch.cp. +Support AF_UNSPEC domains. +More work on spinning performance. + +Revision 1.3 1994/08/10 00:30:30 neeri +Sanitized for universal headers. +Prevent overly fast spinning. + +Revision 1.2 1994/05/01 23:47:34 neeri +Extend fflush() kludge. +Define _lastbuf for MPW 3.2 compatibility. + +Revision 1.1 1994/02/25 02:28:36 neeri +Initial revision + +Revision 0.27 1993/11/24 00:00:00 neeri +Flush stdio before closing + +Revision 0.26 1993/11/22 00:00:00 neeri +Extend two time loser for EBADF + +Revision 0.25 1993/11/12 00:00:00 neeri +Two time loser workaround for flush bug + +Revision 0.24 1993/06/27 00:00:00 neeri +{pre,post}_select + +Revision 0.23 1993/06/27 00:00:00 neeri +ftruncate + +Revision 0.22 1993/06/20 00:00:00 neeri +Further subtleties in console handling + +Revision 0.21 1993/05/21 00:00:00 neeri +Suffixes + +Revision 0.20 1993/05/15 00:00:00 neeri +Try to keep errno always set on error returns + +Revision 0.19 1993/05/13 00:00:00 neeri +Limit Search for configuration resource to application + +Revision 0.18 1993/01/31 00:00:00 neeri +Introducing daemons (pleased to meet you, hope you guess my name) + +Revision 0.17 1993/01/17 00:00:00 neeri +Be more careful about user aborts. + +Revision 0.16 1993/01/03 00:00:00 neeri +GUSIConfiguration + +Revision 0.15 1992/11/25 00:00:00 neeri +Still trying to get standard descriptors for standalone programs right. sigh. + +Revision 0.14 1992/10/05 00:00:00 neeri +Small fix in event dispatching + +Revision 0.13 1992/09/12 00:00:00 neeri +getdtablesize() + +Revision 0.12 1992/08/30 00:00:00 neeri +Move hasPPC to GUSIPPC.cp, AppleTalkIdentity + +Revision 0.11 1992/08/05 00:00:00 neeri +Change the way standard I/O channels are opened + +Revision 0.10 1992/08/03 00:00:00 neeri +Move Scatter/Gather to GUSIBuffer.cp + +Revision 0.9 1992/07/30 00:00:00 neeri +Features with initializers + +Revision 0.8 1992/07/13 00:00:00 neeri +hasProcessMgr + +Revision 0.7 1992/06/27 00:00:00 neeri +choose(), hasNewSF + +Revision 0.6 1992/06/06 00:00:00 neeri +Feature + +Revision 0.5 1992/04/19 00:00:00 neeri +C++ Rewrite + +Revision 0.4 1992/04/18 00:00:00 neeri +Changed read/write/send/recv dispatchers + +Revision 0.3 1992/04/17 00:00:00 neeri +Spin routines + +Revision 0.2 1992/04/16 00:00:00 neeri +User interrupt stuff + +Revision 0.1 1992/03/31 00:00:00 neeri +unix domain socket calls + +*********************************************************************/ + +#include "GUSIFile_P.h" +#include "GUSIMPW_P.h" +#include <SetJmp.h> +#include <Signal.h> +#include <CursorCtl.h> +#include <Resources.h> +#include <Events.h> +#include <Windows.h> +#include <Finder.h> +#include <Script.h> +#include <Events.h> +#include <Traps.h> +#include <CommResources.h> +#include <CTBUtilities.h> +#include <Connections.h> +#include <FileTransfers.h> +#include <Terminals.h> +#include <EPPC.h> +#include <PLStringFuncs.h> +#include <LowMem.h> +#include <Processes.h> + +#if GENERATINGCFM +#include <CodeFragments.h> +#endif + +#pragma segment GUSI + +/***************************** Globals ******************************/ + +GUSIConfiguration GUSIConfig; // Change the order of these declarations +SocketTable Sockets; // and you'll regret it (ARM §12.6.1) +GUSISpinFn GUSISpin = GUSIDefaultSpin; +GUSIExecFn GUSIExec = GUSIDefaultExec; +GUSIFTypeFn GUSIFType = (GUSIFTypeFn)0; +long gGUSISpeed = 1; +static GUSIEvtHandler * evtHandler = nil; +static short evtMask = 0; +static int errorSock = -1; +static int errorType = 0; +static int errorCount = 0; +const int errorMax = 3; +Boolean CatchStdIO = false; + +Feature hasMakeFSSpec( + gestaltFSAttr, + (1<<gestaltHasFSSpecCalls), + (1<<gestaltHasFSSpecCalls)); +Feature hasAlias( + gestaltAliasMgrAttr, + (1<<gestaltAliasMgrPresent), + (1<<gestaltAliasMgrPresent)); +Feature hasNewSF( + gestaltStandardFileAttr, + (1<<gestaltStandardFile58), + (1<<gestaltStandardFile58)); +Feature hasProcessMgr( + gestaltOSAttr, + (1<<gestaltLaunchControl), + (1<<gestaltLaunchControl)); +Feature hasCRM_P( + gestaltCRMAttr, + (1<<gestaltCRMPresent), + (1<<gestaltCRMPresent)); +Feature hasCRM(hasCRM_P, InitCRM); +Feature hasCTB(hasCRM, InitCTBUtilities); +Feature hasStdNBP_P( + gestaltStdNBPAttr, + (1<<gestaltStdNBPPresent), + (1<<gestaltStdNBPPresent)); +Feature hasStdNBP(hasCTB, hasStdNBP_P); +Feature hasAppleEvents( + gestaltAppleEventsAttr, + (1<<gestaltAppleEventsPresent), + (1<<gestaltAppleEventsPresent)); +Feature hasRevisedTimeMgr( + gestaltTimeMgrVersion, + 2L); + +/*********************** Error propagation ************************/ + +#ifdef GUSI_DISPATCH +inline +#endif +int GUSI_error(int err) +{ + if (err) + errno = err; + + return -1; +} + +#ifdef GUSI_DISPATCH +inline +#endif +void * GUSI_error_nil(int err) +{ + if (err) + errno = err; + + return nil; +} + +/*********************** GUSIConfiguration members ************************/ + +#ifndef GUSI_DISPATCH + +Boolean GUSIConfiguration::firstTime = false; +short GUSIConfiguration::we; + +void GUSIConfiguration::GUSILoadConfiguration(Handle h) +{ + typedef GUSIConfigRsrc ** GUSIConfHdl; + GUSIConfHdl config = GUSIConfHdl(h); + long confSize = config ? GetHandleSize(Handle(config)) : 0; + + if (confSize < 4 || !(defaultType = (*config)->defaultType)) + defaultType = 'TEXT'; + if (confSize < 8 || !(defaultCreator = (*config)->defaultCreator)) + defaultCreator = 'MPS '; + if (confSize < 9) + autoSpin = 1; // do automatic spin on read/write + else + autoSpin = (*config)->autoSpin; + + if (confSize < 14) + version = '0102'; + else + version = (*config)->version; + + if (confSize < 10) { + noChdir = false; // Use chdir() + accurStat = false; // st_nlink = # of entries + 2 + hasConsole = false; + noAutoInitGraf = false; + sharedOpen = false; + sigPipe = false; + noAppleEvents = false; + delayConsole = false; + } else { + noChdir = ((*config)->flags & 0x80) != 0; + accurStat = ((*config)->flags & 0x40) != 0; + hasConsole = version >= '0150' && version <= '0180' && ((*config)->flags & 0x08) != 0; + delayConsole = version >= '0181' && ((*config)->flags & 0x20) != 0; + noAppleEvents = version >= '0181' && ((*config)->flags & 0x08) != 0; + noAutoInitGraf = version >= '0174' && ((*config)->flags & 0x04) != 0; + sharedOpen = version >= '0174' && ((*config)->flags & 0x02) != 0; + sigPipe = version >= '0174' && ((*config)->flags & 0x01) != 0; + } + + if (version < '0120' || confSize < 16) + numSuffices = 0; + else + numSuffices = (*config)->numSuffices; + + if (!numSuffices) + suffices = nil; + else if (suffices = new GUSISuffix[numSuffices]) { + HLock((Handle)config); + memcpy(suffices, (*config)->suffices, numSuffices*sizeof(GUSISuffix)); + for (int i=0; i<numSuffices; i++) + for (int j=0; j<4; j++) + if (((char *) (suffices+i))[j] == ' ') + ((char *) (suffices+i))[j] = 0; + } +} + +GUSIConfiguration::GUSIConfiguration() +{ + short oldResFile = CurResFile(); + + if (!firstTime) + we = oldResFile; + else + UseResFile(we); + + Handle config = Get1Resource('GU…I', GUSIRsrcID); + GUSILoadConfiguration(config); + if (!firstTime) { + firstTime = true; + + if (!noChdir) + chdir(":"); + } else + UseResFile(oldResFile); + + ReleaseResource((Handle)config); +} + +void GUSIConfiguration::SetDefaultFType(const TFileSpec & name) const +{ + FInfo info; + + // + // Custom hook if existing + // + if (GUSIFType && GUSIFType(name)) + return; + + // + // Otherwise default behaviour + // + if (HGetFInfo(name.vRefNum, name.parID, name.name, &info)) + return; + + Ptr dot = PLstrrchr(name.name, '.'); + + if (dot && (name.name[0] - (dot-Ptr(name.name))) <= 4) { + char searchsuffix[5]; + + strncpy(searchsuffix, dot+1, name.name[0] - (dot-Ptr(name.name))); + + for (int i = 0; i<numSuffices; i++) + if (!strncmp(suffices[i].suffix, searchsuffix, 4)) { + info.fdType = suffices[i].suffType; + info.fdCreator = suffices[i].suffCreator; + + goto determined; + } + } + + info.fdType = defaultType; + info.fdCreator = defaultCreator; + info.fdFlags &= ~kHasBeenInited; + +determined: + HSetFInfo(name.vRefNum, name.parID, name.name, &info); +} + +void GUSIConfiguration::DoAutoInitGraf() const +{ + if (*(GrafPtr **) LMGetCurrentA5() != &qd.thePort) + InitGraf(&qd.thePort); + const_cast<GUSIConfiguration *>(this)->noAutoInitGraf = true; +} + +#endif // GUSI_DISPATCH + +inline void GUSIConfiguration::DoAutoSpin() const +{ + if (autoSpin) + SAFESPIN(0, SP_AUTO_SPIN, autoSpin); +} + +Boolean GUSIConfiguration::DelayConsole() const +{ + return delayConsole; +} + +/************************ Handle nonstandard consoles *************************/ + +#ifndef GUSI_DISPATCH + +static void InitConsole() +{ + if (MPWDomain::stdopen) { + for (int i = 0; i < 3; i++) { + Socket * sock = MPWDomain::stdopen(i); + + if (sock) + Sockets.Install(sock); + } + } else { + if (open("dev:console", O_RDONLY) < 0) + open("dev:null", O_RDONLY); + if (open("dev:console", O_WRONLY) < 0) + open("dev:null", O_WRONLY); + if (open("dev:console", O_WRONLY) < 0) + open("dev:null", O_WRONLY); + } +} + +void SocketTable::InitConsole() +{ + if (needsConsole) { + needsConsole = false; + ::InitConsole(); + } +} + +#endif // GUSI_DISPATCH + +/************************ External routines *************************/ + +int getdtablesize() +{ + return GUSI_MAX_FD; +} + +int socket(int domain, int type, int protocol) +{ + SocketDomain * dom; + Socket * sock; + int fd; + + Sockets.InitConsole(); + + if (dom = SocketDomain::Domain(domain)) + if (sock = dom->socket(type, protocol)) + if ((fd = Sockets.Install(sock)) != -1) + return fd; + else + delete sock; + + if (!errno) + return GUSI_error(ENOMEM); + else + return -1; +} + +int socketpair(int domain, int type, int protocol, int * sv) +{ + SocketDomain * dom; + Socket * sock[2]; + + Sockets.InitConsole(); + + if (dom = SocketDomain::Domain(domain)) + if (!dom->socketpair(type, protocol, sock)) + if ((sv[0] = Sockets.Install(sock[0])) != -1) + if ((sv[1] = Sockets.Install(sock[1])) != -1) + return 0; + else { + Sockets.Remove(sv[0]); + + goto failInstall; + } + else { +failInstall: + delete sock[0]; + delete sock[1]; + } + + if (!errno) + return GUSI_error(ENOMEM); + else + return -1; +} + +int pipe(int * fd) +{ + GUSIwithUnixSockets(); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) + return -1; + shutdown(fd[0], 1); + shutdown(fd[1], 0); + + return 0; +} + +int choose(int domain, int type, char * prompt, void * constraint, int flags, void * name, int * namelen) +{ + SocketDomain * dom; + + if (dom = SocketDomain::Domain(domain)) + return dom->choose(type, prompt, constraint, flags, name, namelen); + + return -1; +} + +int bind(int s, const struct sockaddr *name, int namelen) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->bind((void *) name, namelen) : -1; +} + +int connect(int s, const struct sockaddr *addr, int addrlen) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->connect((void *) addr, addrlen) : -1; +} + +int listen(int s, int qlen) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->listen(qlen) : -1; +} + +int accept(int s, struct sockaddr *addr, int *addrlen) +{ + Socket * sock = Sockets[s]; + + if (sock) + if (sock = sock->accept(addr, addrlen)) + if ((s = Sockets.Install(sock)) != -1) + return s; + else + delete sock; + + return -1; +} + +int close(int s) +{ + errorSock = -1; + + return Sockets.Remove(s); +} + +#ifdef __MWERKS__ +int read(int s, char *buffer, int buflen) +#else +int read(int s, char *buffer, unsigned buflen) +#endif +{ + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + return sock ? sock->read(buffer, (unsigned) buflen) : -1; +} + +int readv(int s, const struct iovec *iov, int count) +{ + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + if (sock) { + Scatterer scatt(iov, count); + + if (scatt) + return scatt.length(sock->read(scatt.buffer(), scatt.buflen())); + else + return GUSI_error(ENOMEM); + } else + return -1; +} + +int recv(int s, void *buffer, int buflen, int flags) +{ + GUSIConfig.DoAutoSpin(); + + int fromlen = 0; + Socket * sock = Sockets[s]; + + return sock ? sock->recvfrom(buffer, buflen, flags, nil, &fromlen) : -1; +} + +int recvfrom(int s, void *buffer, int buflen, int flags, struct sockaddr *from, int *fromlen) +{ + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + return sock ? sock->recvfrom(buffer, buflen, flags, from, fromlen) : -1; +} + +int recvmsg(int s, struct msghdr *msg, int flags) +{ + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + if (sock) { + Scatterer scatt((struct iovec *)msg->msg_iov, msg->msg_iovlen); + + if (scatt) + return + scatt.length( + sock->recvfrom( + scatt.buffer(), + scatt.buflen(), + flags, + msg->msg_name, + (int *)&msg->msg_namelen)); + else + return GUSI_error(ENOMEM); + } else + return -1; +} + +#ifdef __MWERKS__ +int write(int s, const char *buffer, int buflen) +#else +int write(int s, const char *buffer, unsigned buflen) +#endif +{ + /* fflush() in the MPW stdio library doesn't take no for an answer. + Our workaround is to treat a second subsequent ESHUTDOWN or EBADF as + an invitation to lie by pretending the write worked. + */ + + int len; + + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + if (sock && (len = sock->write((char *) buffer, (unsigned) buflen)) != -1) + return len; + + switch (errno) { + case EINTR: + case EWOULDBLOCK: + case EINPROGRESS: + case EALREADY: + break; + default: + if (GUSIConfig.sigPipe) + raise(SIGPIPE); + if (errorSock == s && errorType == errno) { + if (++errorCount == errorMax) { + errorSock = -1; + + return buflen; + } + } else { + errorSock = s; + errorType = errno; + errorCount= 1; + } + } + return -1; +} + +static int HandleWriteErrors(int retval) +{ + if (retval == -1) + switch (errno) { + case EINTR: + case EWOULDBLOCK: + case EINPROGRESS: + case EALREADY: + break; + default: + if (GUSIConfig.sigPipe) + raise(SIGPIPE); + break; + } + + return retval; +} + +int writev(int s, const struct iovec *iov, int count) +{ + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + if (sock) { + Gatherer gath(iov, count); + + if (gath) + return HandleWriteErrors(gath.length(sock->write(gath.buffer(), gath.buflen()))); + else + return GUSI_error(ENOMEM); + } else + return -1; +} + +int send(int s, const void *buffer, int buflen, int flags) +{ + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + return sock ? HandleWriteErrors(sock->sendto((void *)buffer, buflen, flags, nil, 0)) : -1; +} + +int sendto(int s, const void *buffer, int buflen, int flags, const struct sockaddr *to, int tolen) +{ + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + return sock ? HandleWriteErrors(sock->sendto((void *)buffer, buflen, flags, (void *) to, tolen)) : -1; +} + +int sendmsg(int s, const struct msghdr *msg, int flags) +{ + GUSIConfig.DoAutoSpin(); + + Socket * sock = Sockets[s]; + + if (sock) { + Gatherer gath((struct iovec *) msg->msg_iov, msg->msg_iovlen); + + if (gath) + return + HandleWriteErrors(gath.length( + sock->sendto( + gath.buffer(), + gath.buflen(), + flags, + msg->msg_name, + msg->msg_namelen))); + else + return GUSI_error(ENOMEM); + } else + return -1; +} + +int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + Socket * sock; + long count; + int s; + long starttime, waittime; + fd_set rd, wd, ed; + Boolean r,w,e; + Boolean * canRead; + Boolean * canWrite; + Boolean * exception; + + count = 0; + FD_ZERO(&rd); + FD_ZERO(&wd); + FD_ZERO(&ed); + + if (timeout) + waittime = timeout->tv_sec*60 + timeout->tv_usec/16666; + else + waittime = 2000000000; // Slightly more than a year; close enough to "no timeout" + + starttime = LMGetTicks(); + + // Check files for kosherness + + for (s = 0; s < width ; ++s) + if ( (readfds && FD_ISSET(s,readfds)) + || (writefds && FD_ISSET(s,writefds)) + || (exceptfds && FD_ISSET(s,exceptfds)) + ) + if (!Sockets[s]) + return GUSI_error(EBADF); + + for (s = 0; s < width ; ++s) + if (sock = Sockets[s]) { + r = readfds && FD_ISSET(s,readfds); + w = writefds && FD_ISSET(s,writefds); + e = exceptfds && FD_ISSET(s,exceptfds); + + if (r || w || e) + sock->pre_select(r, w, e); + } + + do { + for (s = 0; s < width ; ++s) { + if (sock = Sockets[s]) { + r = false; + w = false; + e = false; + + canRead = (readfds && FD_ISSET(s,readfds)) ? &r : nil; + canWrite = (writefds && FD_ISSET(s,writefds)) ? &w : nil; + exception = (exceptfds && FD_ISSET(s,exceptfds)) ? &e : nil; + + if (canRead || canWrite || exception) { + count += sock->select(canRead, canWrite, exception); + + if (r) + FD_SET(s,&rd); + if (w) + FD_SET(s,&wd); + if (e) + FD_SET(s,&ed); + } + } + } + if (count) + break; + + SAVE_AND_CLEAR_ERRNO; + SAFESPIN(false, SP_SELECT, waittime); + + if (errno) { + count = -1; + + break; + } + } while (LMGetTicks() - starttime < waittime); + + for (s = 0; s < width ; ++s) + if (sock = Sockets[s]) { + r = readfds && FD_ISSET(s,readfds); + w = writefds && FD_ISSET(s,writefds); + e = exceptfds && FD_ISSET(s,exceptfds); + + if (r || w || e) + sock->post_select(r, w, e); + } + + if (count < 0) + return GUSI_error(EINTR); + + if (readfds) + *readfds = rd; + if (writefds) + *writefds = wd; + if (exceptfds) + *exceptfds = ed; + + return count; +} + +int getsockname(int s, struct sockaddr *name, int *namelen) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->getsockname(name, namelen) : -1; +} + +int getpeername(int s, struct sockaddr *name, int *namelen) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->getpeername(name, namelen) : -1; +} + +int shutdown(int s, int how) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->shutdown(how) : -1; +} + +int fcntl(int s, unsigned int cmd, int arg) +{ + Socket * sock = Sockets[s]; + + if (sock) + return (cmd == F_DUPFD) ? Sockets.Install(sock, arg) : sock->fcntl(cmd, arg); + else + return -1; +} + +int dup(int s) +{ + Socket * sock = Sockets[s]; + + return sock ? Sockets.Install(sock) : -1; +} + +int dup2(int s, int s1) +{ + Socket * sock = Sockets[s]; + + if (!sock) + return -1; + + if (Sockets[s1]) + Sockets.Remove(s1); + + return Sockets.Install(sock, s1); +} + +int ioctl(int s, unsigned int request, long *argp) +{ + Socket * sock = Sockets[s]; + + if (!sock) + return -1; + + return sock->ioctl(request, argp); +} + +int getsockopt(int s, int level, int optname, void *optval, int * optlen) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->getsockopt(level, optname, optval, optlen) : -1; +} + +int setsockopt(int s, int level, int optname, const void *optval, int optlen) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->setsockopt(level, optname, (void *) optval, optlen) : -1; +} + +int fstat(int s, struct stat * buf) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->fstat(buf) : -1; +} + +long lseek(int s, long offset, int whence) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->lseek(offset, whence) : -1; +} + +int ftruncate(int s, long offset) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->ftruncate(offset) : -1; +} + +int isatty(int s) +{ + Socket * sock = Sockets[s]; + + return sock ? sock->isatty() : -1; +} + +void GUSISetHook(GUSIHookCode code, GUSIHook hook) +{ + switch (code) { + case GUSI_SpinHook: + GUSISpin = (GUSISpinFn) hook; + break; + case GUSI_ExecHook: + GUSIExec = (GUSIExecFn) hook; + break; + case GUSI_FTypeHook: + GUSIFType = (GUSIFTypeFn) hook; + break; + case GUSI_SpeedHook: + gGUSISpeed = (long) hook; + break; + } +} + +GUSIHook GUSIGetHook(GUSIHookCode code) +{ + switch (code) { + case GUSI_SpinHook: + return (GUSIHook) GUSISpin; + case GUSI_ExecHook: + return (GUSIHook) GUSIExec; + case GUSI_FTypeHook: + return (GUSIHook) GUSIFType; + case GUSI_SpeedHook: + return (GUSIHook) gGUSISpeed; + break; + default: + return (GUSIHook) nil; + } +} + +int GUSISetEvents(GUSIEvtTable table) +{ + short evt; + + evtHandler = table; + evtMask = 0; + + for (evt = 0; evt<16; ++evt) + if (evtHandler[evt]) + evtMask |= 1 << evt; + + return 0; +} + +GUSIEvtHandler * GUSIGetEvents(void) +{ + return evtHandler; +} + +/*********************** SocketDomain members ***********************/ + +#ifndef GUSI_DISPATCH + +SocketDomain * SocketDomain::domains[GUSI_MAX_DOMAIN]; +ProcessSerialNumber SocketDomain::process; + +SocketDomain * SocketDomain::Domain(int domain) +{ + if (domain < 0 || domain >= GUSI_MAX_DOMAIN || !domains[domain]) { + GUSI_error(EINVAL); + + return nil; + } else + return domains[domain]; +} + +void SocketDomain::Ready() +{ + if (hasProcessMgr) + WakeUpProcess(&process); +} + +SocketDomain::SocketDomain(int domain) +{ +#ifdef PREVENT_DUPLICATE_DOMAINS + if (domains[domain]) { + Str63 msg; + + sprintf((char *) msg+1, "Duplicate declaration for domain %d\n", domain); + msg[0] = (unsigned char)strlen((char *) msg+1); + + DebugStr(msg); + } +#endif + if (domain) // Ignore AF_UNSPEC domains + domains[domain] = this; + + if (hasProcessMgr && !process.highLongOfPSN && !process.lowLongOfPSN) + GetCurrentProcess(&process); +} + +SocketDomain::~SocketDomain() +{ +} + +// Default implementations of socket() just returns an error + +Socket * SocketDomain::socket(int, short) +{ + GUSI_error(EOPNOTSUPP); + + return nil; +} + +// Same with socketpair + +int SocketDomain::socketpair(int, short, Socket **) +{ + return GUSI_error(EOPNOTSUPP); +} + + +int SocketDomain::choose(int, char *, void *, int, void *, int *) +{ + return GUSI_error(EOPNOTSUPP); +} + +void SocketDomain::DontStrip() +{ +} + +/*********************** SocketTable members ************************/ + +static void FlushStdio() +{ + fwalk(fflush); +} + +SocketTable::SocketTable() +{ + atexit(FlushStdio); + + needsConsole = true; +} + +int SocketTable::Install(Socket * sock, int start) +{ + short fd; + + if (start<0 || start >= GUSI_MAX_FD) + return GUSI_error(EINVAL); + + for (fd=start; fd<GUSI_MAX_FD; ++fd) + if (!sockets[fd]) { + sockets[fd] = sock; + + ++sock->refCount; + return fd; + } + + return GUSI_error(EMFILE); +} + +int SocketTable::Remove(int fd) +{ + Socket * sock; + + InitConsole(); + + if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd])) + return GUSI_error(EBADF); + + sockets[fd] = nil; + + if (!--sock->refCount) + delete sock; + + return 0; +} + +Socket * SocketTable::operator[](int fd) +{ + Socket * sock; + + InitConsole(); + + if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd])) { + GUSI_error(EBADF); + + return nil; + } else + return sock; +} + +#ifndef powerc +#pragma far_code +#endif + +SocketTable::~SocketTable() +{ + int i; + + // Flush stdio files (necessary to flush buffers) + + fwalk(fflush); + + // If we didn't need a console so far, we certainly don't need one now! + // Doing this further up would be dangerous for small write only apps + + needsConsole = false; + + // Now close stdio files, just to be sure + + fwalk(fclose); + + // Close all files + + for (i = 0; i<GUSI_MAX_FD; ++i) + if (sockets[i]) + close(i); +} + +#endif // GUSI_DISPATCH + +/********************** sleep()/alarm() ***********************/ + +static long GUSIAlarm = 0; + +int GUSICheckAlarm() +{ + if (GUSIAlarm && LMGetTicks() > GUSIAlarm) { + GUSIAlarm = 0; + raise(SIGALRM); + + return 1; + } else + return 0; +} + +u_int alarm(u_int seconds) +{ + long remaining = GUSIAlarm ? (LMGetTicks() - GUSIAlarm) / 60 : 0; + + GUSIAlarm = seconds ? LMGetTicks() + 60 * seconds : 0; + + return (remaining < 0) ? 0 : (u_int) remaining; +} + +static u_int DoSleep(long ticks) +{ + long wakeup = LMGetTicks() + ticks; + + SAFESPIN(wakeup > LMGetTicks(), SP_SLEEP, wakeup - LMGetTicks()); + + long remaining = (LMGetTicks() - wakeup) / 60; + + return (remaining < 0) ? 0 : (u_int) remaining; +} + +u_int sleep(u_int seconds) +{ + return DoSleep(seconds * 60); +} + +void usleep(u_int useconds) +{ + DoSleep((useconds * 3) / 50000); +} + +/********************** Default spin function ***********************/ + +#ifndef GUSI_DISPATCH + +#ifndef powerc +#pragma smart_code +#endif + +/* Borrowed from tech note 263 */ + +#define kMaskModifiers 0xFE00 // we need the modifiers without the + // command key for KeyTrans +#define kMaskVirtualKey 0x0000FF00 // get virtual key from event message + // for KeyTrans +#define kUpKeyMask 0x0080 +#define kShiftWord 8 // we shift the virtual key to mask it + // into the keyCode for KeyTrans +#define kMaskASCII1 0x00FF0000 // get the key out of the ASCII1 byte +#define kMaskASCII2 0x000000FF // get the key out of the ASCII2 byte +#define kPeriod 0x2E // ascii for a period + +static Boolean CmdPeriod(EventRecord *theEvent) +{ + Boolean fTimeToQuit; + short keyCode; + long virtualKey, keyInfo, lowChar, highChar, keyCId; + UInt32 state; + Handle hKCHR; + Ptr KCHRPtr; + + fTimeToQuit = false; + + if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) { + + // see if the command key is down. If it is, find out the ASCII + // equivalent for the accompanying key. + + if ((*theEvent).modifiers & cmdKey ) { + + virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord; + // And out the command key and Or in the virtualKey + keyCode = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey); + state = 0; + + hKCHR = nil; /* set this to nil before starting */ + KCHRPtr = (Ptr)GetScriptManagerVariable(smKCHRCache); + + if ( !KCHRPtr ) { + keyCId = GetScriptVariable(short(GetScriptManagerVariable(smKeyScript)), smScriptKeys); + + hKCHR = GetResource('KCHR',short(keyCId)); + KCHRPtr = *hKCHR; + } + + if (KCHRPtr) { + keyInfo = KeyTrans(KCHRPtr, keyCode, &state); + if (hKCHR) + ReleaseResource(hKCHR); + } else + keyInfo = (*theEvent).message; + + lowChar = keyInfo & kMaskASCII2; + highChar = (keyInfo & kMaskASCII1) >> 16; + if (lowChar == kPeriod || highChar == kPeriod) + fTimeToQuit = true; + + } // end the command key is down + } // end key down event + + return( fTimeToQuit ); +} + +Boolean GUSIInterrupt() +{ + EvQElPtr eventQ; + + for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead; eventQ; ) + if (CmdPeriod((EventRecord *) &eventQ->evtQWhat)) + return true; + else + eventQ = (EvQElPtr)eventQ->qLink; + + return false; +} + +int StandAlone = 1; +long gGUSISpinControl = 0; + +int GUSIDefaultSpin(spin_msg msg, long arg) +{ + static Boolean inForeground = true; + WindowPtr win; + EventRecord ev; + long sleepTime = 6; // 1/10 of a second by default + short mask = osMask|highLevelEventMask|mDownMask|evtMask; + + GUSIConfig.AutoInitGraf(); + + if (inForeground) { + register long contrib = (msg == SP_AUTO_SPIN) ? arg : gGUSISpeed; + gGUSISpinControl += contrib; + // Tweak when a spin point has been overshot + RotateCursor((gGUSISpinControl & 31) < contrib ? 32 : gGUSISpinControl); + } + + if (GUSIInterrupt()) + goto interrupt; + + if (!StandAlone && inForeground) // For MPW tools, SpinCursor already calls WNE + if (!GUSIConfig.noAppleEvents) // but it no longer reports AppleEvents + mask = highLevelEventMask|evtMask; + else + return 0; + + switch (msg) { + case SP_SLEEP: + case SP_SELECT: + if (arg >= sleepTime) // Only sleep if patience guaranteed + break; + // Otherwise, fall through + case SP_AUTO_SPIN: + sleepTime = 0; + break; + default: + break; + } + + if (WaitNextEvent(mask, &ev, sleepTime, nil)) + switch (ev.what) { + case mouseDown: + if (!evtHandler || !evtHandler[mouseDown]) + if (FindWindow(ev.where, &win) == inSysWindow) + SystemClick(&ev, win); + + break; + case osEvt: + if (ev.message & 1) + inForeground = true; + else + inForeground = false; + break; + case kHighLevelEvent: + if (!evtHandler || !evtHandler[kHighLevelEvent]) + if (hasAppleEvents) // actually pretty likely, if we get HL Events + AEProcessAppleEvent(&ev); // Ignore errors + break; + default: + break; + } + + if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what]) + evtHandler[ev.what](&ev); + + return 0; + +interrupt: + FlushEvents(-1, 0); + + return -1; +} + +/************************** Feature members **************************/ + +Feature::Feature(unsigned short trapNum, TrapType tTyp) +{ + good = + NGetTrapAddress(trapNum, tTyp) != NGetTrapAddress(_Unimplemented, ToolTrap); +} + +Feature::Feature(OSType type, long value) +{ + long attr; + + good = (!Gestalt(type, &attr) && (attr >= value)); +} + +Feature::Feature(OSType type, long mask, long value) +{ + long attr; + + good = (!Gestalt(type, &attr) && ((attr & mask) == value)); +} + +Feature::Feature(const Feature & precondition, OSErrInitializer init) +{ + good = precondition && !init(); +} + +Feature::Feature(OSErrInitializer init) +{ + good = !init(); +} + +Feature::Feature(const Feature & precondition, voidInitializer init) +{ + if (precondition) { + good = true; + init(); + } else + good = false; +} + +Feature::Feature(voidInitializer init) +{ + good = true; + init(); +} + +Feature::Feature(const Feature & cond1, const Feature & cond2) +{ + good = cond1 && cond2; +} + +OSErr AppleTalkIdentity(short & net, short & node) +{ + static short mynet; + static short mynode; + static OSErr err = 1; + + if (err == 1) + if (!(err = MPPOpen())) + err = GetNodeAddress(&mynode, &mynet); + + + net = mynet; + node = mynode; + + return err; +} + +/************************** Setup suppport **************************/ + +/* Pray that the following function never inlines GUSISetup */ + +void GUSIDefaultSetup() +{ + GUSISetup(GUSIwithAppleTalkSockets); + GUSISetup(GUSIwithInternetSockets); + GUSISetup(GUSIwithPAPSockets); + GUSISetup(GUSIwithPPCSockets); + GUSISetup(GUSIwithUnixSockets); + GUSISetup(GUSIwithSIOUXSockets); +} + +void GUSISetup(void (*proc)()) +{ + proc(); +} + +void GUSILoadConfiguration(Handle hdl) +{ + GUSIConfig.GUSILoadConfiguration(hdl); +} + +#endif // GUSI_DISPATCH diff --git a/Mac/GUSI-mods/into-src/GUSINetDB.cp b/Mac/GUSI-mods/into-src/GUSINetDB.cp new file mode 100644 index 0000000..bc435b6 --- /dev/null +++ b/Mac/GUSI-mods/into-src/GUSINetDB.cp @@ -0,0 +1,579 @@ +/********************************************************************* +Project : GUSI - Grand Unified Socket Interface +File : GUSINetDB.cp - Convert internet names to adresses +Author : Matthias Neeracher + + This file was derived from the socket library by + + Charlie Reiman <creiman@ncsa.uiuc.edu> and + Tom Milligan <milligan@madhaus.utcs.utoronto.ca> + +Language : MPW C++ + +$Log$ +Revision 1.1 1998/08/18 14:52:38 jack +Putting Python-specific GUSI modifications under CVS. + +Revision 1.3 1994/08/10 00:07:30 neeri +Sanitized for universal headers. + +Revision 1.2 1994/05/01 23:43:31 neeri +getservbyname() without /etc/services would fail. + +Revision 1.1 1994/02/25 02:29:36 neeri +Initial revision + +Revision 0.5 1993/10/31 00:00:00 neeri +Deferred opening of resolver + +Revision 0.4 1993/07/29 00:00:00 neeri +Real getservent code (adapted from Sak Wathanasin) + +Revision 0.3 1993/01/19 00:00:00 neeri +Can't set aliases to NULL. + +Revision 0.2 1992/11/21 00:00:00 neeri +Remove force_active + +Revision 0.1 1992/09/14 00:00:00 neeri +Maybe it works, maybe it doesn't + +*********************************************************************/ + +#include "GUSIINET_P.h" + +#include "TFileSpec.h" +#include "Folders.h" +#include "PLStringFuncs.h" + +#ifdef __MWERKS__ +// +// I disapprove of the way dnr.c is written +// This disapproval gets stronger with every version +// +#include "dnr.c" +#pragma require_prototypes reset +#pragma cplusplus reset +#endif + +#if GENERATING68K +#pragma segment GUSIINET +#endif + +static pascal void DNRDone(struct hostInfo *, Boolean * done) +{ + *done = true; +} + +#if GENERATINGCFM +RoutineDescriptor uDNRDone = + BUILD_ROUTINE_DESCRIPTOR(uppResultProcInfo, DNRDone); +#else +#define uDNRDone DNRDone +#endif + +int h_errno; + +/* + * Gethostbyname and gethostbyaddr each return a pointer to an + * object with the following structure describing an Internet + * host referenced by name or by address, respectively. This + * structure contains the information obtained from the MacTCP + * name server. + * + * struct hostent + * { + * char *h_name; + * char **h_aliases; + * int h_addrtype; + * int h_length; + * char **h_addr_list; + * }; + * #define h_addr h_addr_list[0] + * + * The members of this structure are: + * + * h_name Official name of the host. + * + * h_aliases A zero terminated array of alternate names for the host. + * + * h_addrtype The type of address being returned; always AF_INET. + * + * h_length The length, in bytes, of the address. + * + * h_addr_list A zero terminated array of network addresses for the host. + * + * Error return status from gethostbyname and gethostbyaddr is + * indicated by return of a null pointer. The external integer + * h_errno may then be checked to see whether this is a + * temporary failure or an invalid or unknown host. The + * routine herror can be used to print an error message + * describing the failure. If its argument string is non-NULL, + * it is printed, followed by a colon and a space. The error + * message is printed with a trailing newline. + * + * h_errno can have the following values: + * + * HOST_NOT_FOUND No such host is known. + * + * TRY_AGAIN This is usually a temporary error and + * means that the local server did not + * receive a response from an authoritative + * server. A retry at some later time may + * succeed. + * + * NO_RECOVERY Some unexpected server failure was encountered. + * This is a non-recoverable error. + * + * NO_DATA The requested name is valid but does not + * have an IP address; this is not a + * temporary error. This means that the name + * is known to the name server but there is + * no address associated with this name. + * Another type of request to the name server + * using this domain name will result in an + * answer; for example, a mail-forwarder may + * be registered for this domain. + * (NOT GENERATED BY THIS IMPLEMENTATION) + */ + +static struct hostInfo macHost; + +#define MAXALIASES 0 +static char *aliasPtrs[MAXALIASES+1] = {NULL}; +static ip_addr *addrPtrs[NUM_ALT_ADDRS+1]; + +static struct hostent unixHost = +{ + macHost.cname, + aliasPtrs, + AF_INET, + sizeof(ip_addr), + (char **) addrPtrs +}; + +inline struct in_addr make_in_addr(ip_addr addr) +{ + struct in_addr res; + + res.s_addr = addr; + + return res; +} + +struct hostent * gethostbyname(char *name) +{ + Boolean done; + int i; + + if (!strcmp(name, "localhost")) { + in_addr ipaddr; + + ipaddr = make_in_addr(ip_addr(gethostid())); + + if (ipaddr.s_addr) + return gethostbyaddr((char *) &ipaddr, sizeof(in_addr), AF_INET); + + h_errno = HOST_NOT_FOUND; + + return NULL; + } + + if (INETSockets.Resolver()) { + h_errno = NO_RECOVERY; + return NULL; + } + + for (i=0; i<NUM_ALT_ADDRS; i++) + macHost.addr[i] = 0; + + done = false; + + if (StrToAddr(name, &macHost, ResultUPP(&uDNRDone), (char *) &done) == cacheFault) + SPINP(!done,SP_NAME,0L); + + switch (macHost.rtnCode) { + case noErr: break; + + case nameSyntaxErr: h_errno = HOST_NOT_FOUND; return(NULL); + case cacheFault: h_errno = NO_RECOVERY; return(NULL); + case noResultProc: h_errno = NO_RECOVERY; return(NULL); + case noNameServer: h_errno = HOST_NOT_FOUND; return(NULL); + case authNameErr: h_errno = HOST_NOT_FOUND; return(NULL); + case noAnsErr: h_errno = TRY_AGAIN; return(NULL); + case dnrErr: h_errno = NO_RECOVERY; return(NULL); + case outOfMemory: h_errno = TRY_AGAIN; return(NULL); + default: h_errno = NO_RECOVERY; return(NULL); + } + + /* was the 'name' an IP address? */ + if (macHost.cname[0] == 0) { + h_errno = HOST_NOT_FOUND; + return(NULL); + } + + /* for some reason there is a dot at the end of the name */ + i = int(strlen(macHost.cname)) - 1; + if (macHost.cname[i] == '.') + macHost.cname[i] = 0; + + for (i=0; i<NUM_ALT_ADDRS && macHost.addr[i]!=0; i++) + addrPtrs[i] = (ip_addr *) &macHost.addr[i]; + + addrPtrs[i] = NULL; + + return &unixHost; +} + +struct hostent * gethostbyaddr(const char *addrP, int, int) +{ + Boolean done; + int i; + + if (INETSockets.Resolver()) { + h_errno = NO_RECOVERY; + return NULL; + } + + for (i=0; i<NUM_ALT_ADDRS; i++) + macHost.addr[i] = 0; + + done = false; + + ip_addr addr = FIX_LOOPBACK(*(ip_addr *)addrP); + + if (AddrToName(addr, &macHost, ResultUPP(&uDNRDone), (char *) &done) == cacheFault) + SPINP(!done,SP_ADDR,0L); + + switch (macHost.rtnCode) { + case noErr: break; + + case cacheFault: h_errno = NO_RECOVERY; return(NULL); + case noNameServer: h_errno = HOST_NOT_FOUND; return(NULL); + case authNameErr: h_errno = HOST_NOT_FOUND; return(NULL); + case noAnsErr: h_errno = TRY_AGAIN; return(NULL); + case dnrErr: h_errno = NO_RECOVERY; return(NULL); + case outOfMemory: h_errno = TRY_AGAIN; return(NULL); + default: h_errno = NO_RECOVERY; return(NULL); + } + + /* for some reason there is a dot at the end of the name */ + i = int(strlen(macHost.cname)) - 1; + if (macHost.cname[i] == '.') + macHost.cname[i] = 0; + + /* For some reason, the IP address usually seems to be set to 0 */ + if (!macHost.addr[0]) + macHost.addr[0] = addr; + + for (i=0; i<NUM_ALT_ADDRS; i++) + addrPtrs[i] = (ip_addr *) &macHost.addr[i]; + + addrPtrs[NUM_ALT_ADDRS] = NULL; + + return &unixHost; +} + +char * inet_ntoa(struct in_addr inaddr) +{ + if (INETSockets.Resolver()) { + h_errno = NO_RECOVERY; + return NULL; + } + + (void) AddrToStr(inaddr.s_addr, macHost.cname); + + return macHost.cname; +} + +struct in_addr inet_addr(char *address) +{ + if (INETSockets.Resolver()) { + h_errno = NO_RECOVERY; + return make_in_addr(0xFFFFFFFF); + } + + if (StrToAddr(address,&macHost,NULL,NULL) != noErr) + return make_in_addr(0xFFFFFFFF); + + /* was the 'address' really a name? */ + if (macHost.cname[0] != 0) + return make_in_addr(0xFFFFFFFF); + + return make_in_addr(macHost.addr[0]); +} + +/* + * gethostid() + * + * Get internet address of current host + */ + +long gethostid() +{ + static long sHostID = 0; + if (sHostID) + return sHostID; + + struct GetAddrParamBlock pbr; + + pbr.ioCRefNum = INETSockets.Driver(); + pbr.csCode = ipctlGetAddr; + + if (PBControlSync(ParmBlkPtr(&pbr))) + return 0; + else + return sHostID = (long)pbr.ourAddress; +} + +/* + * gethostname() + * + * Try to get my host name from DNR. If it fails, just return my + * IP address as ASCII. This is non-standard, but it's a mac, + * what do you want me to do? + */ + +int gethostname(char *machname, int buflen) +{ + static char * sHostName = nil; + + if (!sHostName) { + in_addr ipaddr; + struct hostent *hp; + + ipaddr = make_in_addr(ip_addr(gethostid())); + + if (!ipaddr.s_addr) // TCP/IP not up at all + return GUSI_error(ENETDOWN); + + hp = gethostbyaddr((char *) &ipaddr, sizeof(in_addr), AF_INET); + + if (!hp) { + // No good name + if (buflen < 16) // Not enough space + return GUSI_error(EINVAL); + sprintf(machname, "%d.%d.%d.%d", + ipaddr.s_addr>>24, + ipaddr.s_addr>>16 & 0xff, + ipaddr.s_addr>>8 & 0xff, + ipaddr.s_addr & 0xff); + return 0; + } else { + // We only cache satisfactory replies in sHostName + sHostName = new char[strlen(hp->h_name)+1]; + strcpy(sHostName, hp->h_name); + } + } + strncpy(machname, sHostName, unsigned(buflen)); + machname[buflen-1] = 0; /* extra safeguard */ + + return 0; +} + + +/* + * getservbybname() + * + */ + +static char * servlist[] = +{ + "echo 7/udp", + "discard 9/udp", + "time 37/udp", + "domain 53/udp", + "sunrpc 111/udp", + "tftp 69/udp", + "biff 512/udp", + "who 513/udp", + "talk 517/udp", + "ftp-data 20/tcp", + "ftp 21/tcp", + "telnet 23/tcp", + "smtp 25/tcp", + "time 37/tcp", + "whois 43/tcp", + "domain 53/tcp", + "hostnames 101/tcp", + "nntp 119/tcp", + "finger 79/tcp", + "ntp 123/tcp", + "uucp 540/tcp", + NULL +}; + +static char servline[128]; +static struct servent serv; +static FILE * servfil; +static int servptr; +static char * servalias[8]; +static int servstay = 0; + +void setservent(int stayopen) +{ + if (servfil && servfil != (FILE *) -1) { + rewind(servfil); + } + servptr = 0; + servstay = servstay || stayopen; +} + +void endservent() +{ + if (servfil && servfil != (FILE *) -1) { + fclose(servfil); + servfil = NULL; + } + + servstay = 0; +} + +struct servent * getservent() +{ + char * p; + int aliascount; + + if (!servfil) { + TFileSpec serv; + + if (!FindFolder( + kOnSystemDisk, + kPreferencesFolderType, + kDontCreateFolder, + &serv.vRefNum, + &serv.parID) + ) { + PLstrcpy(serv.name, (StringPtr) "\p/etc/services"); + + if (servfil = fopen(serv.FullPath(), "r")) + goto retry; + } + servfil = (FILE *) -1; + servptr = 0; + } + +retry: + if (servfil == (FILE *) -1) + if (!servlist[servptr]) + return (struct servent *) NULL; + else + strcpy(servline, servlist[servptr++]); + else if (!(fgets(servline, 128, servfil))) + return (struct servent *) NULL; + + if (p = strpbrk(servline, "#\n\r")) + *p = 0; + if (!servline[0]) + goto retry; + + if (!(serv.s_name = strtok(servline, " \t"))) + goto retry; + + if (!(p = strtok(NULL, " \t"))) + goto retry; + + if (!(serv.s_proto = strpbrk(p, "/,"))) + goto retry; + + *serv.s_proto++ = 0; + serv.s_port = htons(atoi(p)); + serv.s_aliases = servalias; + + for (aliascount = 0; aliascount < 7; ) + if (!(servalias[aliascount++] = strtok(NULL, " \t"))) + break; + + servalias[aliascount] = NULL; + + return &serv; +} + +struct servent * getservbyname(const char * name, const char * proto) +{ + struct servent * ent; + char ** al; + setservent(0); + + while (ent = getservent()) { + if (!strcmp(name, ent->s_name)) + goto haveName; + + for (al = ent->s_aliases; *al; ++al) + if (!strcmp(name, *al)) + goto haveName; + + continue; +haveName: + if (!proto || !strcmp(proto, ent->s_proto)) + break; + } + + if (!servstay) + endservent(); + + return ent; +} + +struct servent * getservbyport(int port, const char * proto) +{ + struct servent * ent; + + setservent(0); + + while (ent = getservent()) + if (port == ent->s_port && (!proto || !strcmp(proto, ent->s_proto))) + break; + + if (!servstay) + endservent(); + + return ent; +} + +static char tcp[] = "tcp"; +static char udp[] = "udp"; +#define MAX_PROTOENT 10 +static struct protoent protoents[MAX_PROTOENT]; +static int protoent_count=0; + +struct protoent * getprotobyname(const char * name) +{ + struct protoent *pe; + + pe = &protoents[protoent_count]; + if (strcmp(name, "udp") == 0) { + pe->p_name = udp; + pe->p_proto = IPPROTO_UDP; + } else if (strcmp (name, "tcp") == 0) { + pe->p_name = tcp; + pe->p_proto = IPPROTO_TCP; + } else { + errno = EPROTONOSUPPORT; + return NULL; + } + pe->p_aliases = aliasPtrs; + protoent_count = (protoent_count +1) % MAX_PROTOENT; + return pe; +} + +struct protoent * getprotobynumber(int proto) +{ + struct protoent *pe; + + pe = &protoents[protoent_count]; + if (proto == IPPROTO_UDP) { + pe->p_name = udp; + pe->p_proto = IPPROTO_UDP; + } else if (proto == IPPROTO_TCP) { + pe->p_name = tcp; + pe->p_proto = IPPROTO_TCP; + } else { + errno = EPROTONOSUPPORT; + return NULL; + } + pe->p_aliases = aliasPtrs; + protoent_count = (protoent_count +1) % MAX_PROTOENT; + return pe; +} + diff --git a/Mac/GUSI-mods/into-src/GUSISIOUX.cp b/Mac/GUSI-mods/into-src/GUSISIOUX.cp new file mode 100644 index 0000000..24b98b0 --- /dev/null +++ b/Mac/GUSI-mods/into-src/GUSISIOUX.cp @@ -0,0 +1,246 @@ +/********************************************************************* +Project : GUSI - Grand unified socket interface +File : GUSISIOUX.cp - Interface to Metrowerks SIOUX library +Author : Matthias Neeracher +Language : MPW C/C++ + +$Log$ +Revision 1.1 1998/08/18 14:52:38 jack +Putting Python-specific GUSI modifications under CVS. + +*********************************************************************/ + +#include <GUSIFile_P.h> +#include <ioctl.h> +#include <console.h> + +#include <Events.h> +#include <LowMem.h> + +/************************ SIOUXSocket members ************************/ + +/* This declaration lies about the return type */ +extern "C" void SIOUXHandleOneEvent(EventRecord *userevent); + +GUSIEvtHandler GUSISIOUXEvents[] = { + SIOUXHandleOneEvent, // nullEvent + + SIOUXHandleOneEvent, // mouseDown + SIOUXHandleOneEvent, // mouseUp + nil, // keyDown + nil, + + nil, // autoKey + SIOUXHandleOneEvent, // updateEvt + SIOUXHandleOneEvent, // diskEvt + SIOUXHandleOneEvent, // activateEvt + + nil, + nil, + nil, + nil, + + nil, + nil, + SIOUXHandleOneEvent, // osEvt + nil, + + nil, + nil, + nil, + nil, + + nil, + nil, + nil, +}; + +/************************ Declaration of SIOUXSocket ************************/ + +class SIOUXSocket : public Socket { + friend class SIOUXSocketDomain; + + SIOUXSocket(); + + virtual ~SIOUXSocket(); +protected: + int initialized; + void DoInitialize(void); +public: + virtual int read(void * buffer, int buflen); + virtual int write(void * buffer, int buflen); + virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception); + virtual int ioctl(unsigned int request, void *argp); + virtual int isatty(); +}; + +class SIOUXSocketDomain : public FileSocketDomain { + SIOUXSocket * singleton; +public: + SIOUXSocketDomain() : FileSocketDomain(AF_UNSPEC, true, false), singleton(nil) { } + + virtual Boolean Yours(const GUSIFileRef & ref, Request request); + virtual Socket * open(const GUSIFileRef & ref, int oflag); +}; + +#if GENERATING68K +#pragma segment SIOUX +#endif + +/************************ SIOUXSocket members ************************/ + +void SIOUXSocket::DoInitialize() +{ + if ( initialized ) return; + initialized++; + InstallConsole(0); + GUSISetEvents(GUSISIOUXEvents); +} + +SIOUXSocket::SIOUXSocket() +{ + initialized = 0; + if ( !GUSIConfig.DelayConsole() ) + DoInitialize(); +} + +SIOUXSocket::~SIOUXSocket() +{ + RemoveConsole(); +} + +int SIOUXSocket::ioctl(unsigned int request, void *) +{ + if ( !initialized) DoInitialize(); + switch (request) { + case FIOINTERACTIVE: + return 0; + default: + return GUSI_error(EOPNOTSUPP); + } +} + +int SIOUXSocket::read(void * buffer, int buflen) +{ + if ( !initialized) DoInitialize(); + fflush(stdout); + + return ReadCharsFromConsole((char *) buffer, buflen); +} + +int SIOUXSocket::write(void * buffer, int buflen) +{ + if ( !initialized) DoInitialize(); + return WriteCharsToConsole((char *) buffer, buflen); +} + +static Boolean input_pending() +{ + QHdrPtr eventQueue = LMGetEventQueue(); + EvQElPtr element = (EvQElPtr)eventQueue->qHead; + + // now, count the number of pending keyDown events. + while (element != nil) { + if (element->evtQWhat == keyDown || element->evtQWhat == autoKey) + return true; + element = (EvQElPtr)element->qLink; + } + + return false; +} + +int SIOUXSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception) +{ + int goodies = 0; + + if ( !initialized) DoInitialize(); + fflush(stdout); + + if (canRead) + if (*canRead = input_pending()) + ++goodies; + + if (canWrite) { + *canWrite = true; + ++goodies; + } + + if (exception) + *exception = false; + + return goodies; +} + +int SIOUXSocket::isatty() +{ + return 1; +} + +/********************* SIOUXSocketDomain members **********************/ + +#ifdef MSLGUSI +#ifndef SFIOGUSI + extern void GUSISetupMSLSIOUX(); +#endif +#endif + +extern "C" void GUSIwithSIOUXSockets() +{ + static SIOUXSocketDomain SIOUXSockets; + SIOUXSockets.DontStrip(); +#ifdef MSLGUSI +#ifndef SFIOGUSI + GUSISetupMSLSIOUX(); +#endif +#endif +} + +Boolean SIOUXSocketDomain::Yours(const GUSIFileRef & ref, FileSocketDomain::Request request) +{ + if (ref.spec || (request != willOpen && request != willStat)) + return false; + + switch (ref.name[4] | 0x20) { + case 's': + if ((ref.name[5] | 0x20) != 't' || (ref.name[6] | 0x20) != 'd') + return false; + switch (ref.name[7] | 0x20) { + case 'i': + if ((ref.name[8] | 0x20) != 'n' || ref.name[9]) + return false; + return true; + case 'o': + if ((ref.name[8] | 0x20) != 'u' || (ref.name[9] | 0x20) != 't' || ref.name[10]) + return false; + return true; + case 'e': + if ((ref.name[8] | 0x20) != 'r' || (ref.name[9] | 0x20) != 'r' || ref.name[10]) + return false; + return true; + default: + return false; + } + case 'c': + if ( (ref.name[5] | 0x20) != 'o' || (ref.name[6] | 0x20) != 'n' + || (ref.name[7] | 0x20) != 's' || (ref.name[8] | 0x20) != 'o' + || (ref.name[9] | 0x20) != 'l' || (ref.name[10] | 0x20) != 'e') + return false; + switch (ref.name[11]) { + case 0: + return true; + default: + return false; + } + default: + return false; + } +} + +Socket * SIOUXSocketDomain::open(const GUSIFileRef &, int) +{ + if (!singleton) + singleton = new SIOUXSocket(); + ++*singleton; + + return singleton; +} |