Jack Jansen | 1d6a6ea | 1998-08-18 14:52:38 +0000 | [diff] [blame] | 1 | /********************************************************************* |
| 2 | Project : GUSI - Grand Unified Socket Interface |
| 3 | File : GUSI_P.h - Private stuff |
| 4 | Author : Matthias Neeracher |
| 5 | Language : MPW C/C++ |
| 6 | |
| 7 | $Log$ |
Jack Jansen | 9c940ca | 2000-09-12 20:24:50 +0000 | [diff] [blame] | 8 | Revision 1.1 2000/09/12 20:24:46 jack |
| 9 | Moved to Unsupported. |
| 10 | |
Jack Jansen | 1d6a6ea | 1998-08-18 14:52:38 +0000 | [diff] [blame] | 11 | Revision 1.1 1998/08/18 14:52:33 jack |
| 12 | Putting Python-specific GUSI modifications under CVS. |
| 13 | |
| 14 | Revision 1.3 1994/12/31 01:30:26 neeri |
| 15 | Reorganize filename dispatching. |
| 16 | |
| 17 | Revision 1.2 1994/08/10 00:41:05 neeri |
| 18 | Sanitized for universal headers. |
| 19 | |
| 20 | Revision 1.1 1994/02/25 02:57:01 neeri |
| 21 | Initial revision |
| 22 | |
| 23 | Revision 0.22 1993/07/17 00:00:00 neeri |
| 24 | GUSIRingBuffer::proc -> defproc |
| 25 | |
| 26 | Revision 0.21 1993/07/17 00:00:00 neeri |
| 27 | GUSIO_MAX_DOMAIN -> AF_MAX |
| 28 | |
| 29 | Revision 0.20 1993/06/27 00:00:00 neeri |
| 30 | Socket::{pre,post}_select |
| 31 | |
| 32 | Revision 0.19 1993/06/27 00:00:00 neeri |
| 33 | Socket::ftruncate |
| 34 | |
| 35 | Revision 0.18 1993/02/09 00:00:00 neeri |
| 36 | Socket::lurking, Socket::lurkdescr |
| 37 | |
| 38 | Revision 0.17 1993/01/31 00:00:00 neeri |
| 39 | GUSIConfiguration::daemon |
| 40 | |
| 41 | Revision 0.16 1993/01/17 00:00:00 neeri |
| 42 | Destructors for Socketdomain |
| 43 | |
| 44 | Revision 0.15 1993/01/17 00:00:00 neeri |
| 45 | SAFESPIN |
| 46 | |
| 47 | Revision 0.14 1993/01/03 00:00:00 neeri |
| 48 | GUSIConfig |
| 49 | |
| 50 | Revision 0.13 1992/09/24 00:00:00 neeri |
| 51 | Include GUSIRsrc_P.h |
| 52 | |
| 53 | Revision 0.12 1992/09/13 00:00:00 neeri |
| 54 | SPINVOID didn't return |
| 55 | |
| 56 | Revision 0.11 1992/08/30 00:00:00 neeri |
| 57 | AppleTalkIdentity() |
| 58 | |
| 59 | Revision 0.10 1992/08/03 00:00:00 neeri |
| 60 | RingBuffer |
| 61 | |
| 62 | Revision 0.9 1992/07/30 00:00:00 neeri |
| 63 | Initializer Features |
| 64 | |
| 65 | Revision 0.8 1992/07/26 00:00:00 neeri |
| 66 | UnixSockets.choose() |
| 67 | |
| 68 | Revision 0.7 1992/07/13 00:00:00 neeri |
| 69 | Make AppleTalkSockets global |
| 70 | |
| 71 | Revision 0.6 1992/06/27 00:00:00 neeri |
| 72 | choose(), hasNewSF |
| 73 | |
| 74 | Revision 0.5 1992/06/07 00:00:00 neeri |
| 75 | Feature |
| 76 | |
| 77 | Revision 0.4 1992/05/21 00:00:00 neeri |
| 78 | Implemented select() |
| 79 | |
| 80 | Revision 0.3 1992/04/19 00:00:00 neeri |
| 81 | C++ rewrite |
| 82 | |
| 83 | Revision 0.2 1992/04/18 00:00:00 neeri |
| 84 | changed read/write/send/recv dispatchers |
| 85 | |
| 86 | Revision 0.1 1992/04/18 00:00:00 neeri |
| 87 | ppc Domain |
| 88 | |
| 89 | *********************************************************************/ |
| 90 | |
| 91 | #ifndef __GUSI_P__ |
| 92 | #define __GUSI_P__ |
| 93 | |
| 94 | #define __useAppleExts__ |
| 95 | |
| 96 | #include <GUSI.h> |
| 97 | #include <GUSIRsrc_P.h> |
| 98 | #include <TFileSpec.h> |
| 99 | |
| 100 | |
| 101 | #include <sys/errno.h> |
| 102 | #include <sys/uio.h> |
| 103 | #include <sys/socket.h> |
| 104 | |
| 105 | extern "C" { |
| 106 | |
| 107 | #include <stdio.h> |
| 108 | #include <string.h> |
| 109 | |
| 110 | int GUSI_error(int err); |
| 111 | void * GUSI_error_nil(int err); |
| 112 | } |
| 113 | |
| 114 | #include <Memory.h> |
| 115 | #include <Gestalt.h> |
| 116 | #include <Traps.h> |
| 117 | #include <AppleEvents.h> |
| 118 | #include <Processes.h> |
| 119 | #include <MixedMode.h> |
| 120 | |
| 121 | #if MSLGUSI |
| 122 | using namespace std; |
| 123 | #endif |
| 124 | |
| 125 | #if GENERATING68K |
| 126 | #pragma segment GUSI |
| 127 | #endif |
| 128 | |
| 129 | #define GUSI_MAX_DOMAIN AF_MAX |
| 130 | #define DEFAULT_BUFFER_SIZE 4096 |
| 131 | |
| 132 | /* |
| 133 | * In use and shutdown status. |
| 134 | */ |
| 135 | #define SOCK_STATUS_USED 0x1 /* Used socket table entry */ |
| 136 | #define SOCK_STATUS_NOREAD 0x2 /* No more reading allowed from socket */ |
| 137 | #define SOCK_STATUS_NOWRITE 0x4 /* No more writing allowed to socket */ |
| 138 | |
| 139 | /* |
| 140 | * Socket connection states. |
| 141 | */ |
| 142 | #define SOCK_STATE_NO_STREAM 0 /* Socket doesn't have a MacTCP stream yet */ |
| 143 | #define SOCK_STATE_UNCONNECTED 1 /* Socket is unconnected. */ |
| 144 | #define SOCK_STATE_LISTENING 2 /* Socket is listening for connection. */ |
| 145 | #define SOCK_STATE_LIS_CON 3 /* Socket is in transition from listen to connected. */ |
| 146 | #define SOCK_STATE_CONNECTING 4 /* Socket is initiating a connection. */ |
| 147 | #define SOCK_STATE_CONNECTED 5 /* Socket is connected. */ |
| 148 | #define SOCK_STATE_CLOSING 6 /* Socket is closing */ |
| 149 | #define SOCK_STATE_LIS_CLOSE 7 /* Socket closed while listening */ |
| 150 | |
| 151 | #define min(a,b) ( (a) < (b) ? (a) : (b)) |
| 152 | #define max(a,b) ( (a) > (b) ? (a) : (b)) |
| 153 | |
| 154 | extern GUSISpinFn GUSISpin; |
| 155 | extern "C" int GUSIDefaultSpin(spin_msg, long); |
| 156 | extern int GUSICheckAlarm(); |
| 157 | |
| 158 | #define GUSI_INTERRUPT(mesg,param) (GUSICheckAlarm() || (GUSISpin && (*GUSISpin)(mesg,param))) |
| 159 | |
| 160 | /* SPIN returns a -1 on user cancel for fn returning integers */ |
| 161 | #define SPIN(cond,mesg,param) \ |
| 162 | do { \ |
| 163 | if (GUSI_INTERRUPT(mesg,param)) \ |
| 164 | return GUSI_error(EINTR); \ |
| 165 | } while(cond) |
| 166 | |
| 167 | /* SPINP returns a NULL on user cancel, for fn returning pointers */ |
| 168 | #define SPINP(cond,mesg,param) \ |
| 169 | do { \ |
| 170 | if (GUSI_INTERRUPT(mesg,param)) { \ |
| 171 | GUSI_error(EINTR); \ |
| 172 | return NULL; \ |
| 173 | } \ |
| 174 | } while(cond) |
| 175 | |
| 176 | /* SPINVOID just returns on user cancel, for fn returning void */ |
| 177 | #define SPINVOID(cond,mesg,param) \ |
| 178 | do { \ |
| 179 | if (GUSI_INTERRUPT(mesg,param)) { \ |
| 180 | GUSI_error(EINTR); \ |
| 181 | return; \ |
| 182 | } \ |
| 183 | } while(cond) |
| 184 | |
| 185 | /* SAFESPIN doesn't return, you have to check errno */ |
| 186 | #define SAFESPIN(cond,mesg,param) \ |
| 187 | do { \ |
| 188 | if (GUSI_INTERRUPT(mesg,param)) { \ |
| 189 | GUSI_error(EINTR); \ |
| 190 | break; \ |
| 191 | } else \ |
| 192 | errno = 0; \ |
| 193 | } while(cond) |
| 194 | |
| 195 | // |
| 196 | // Library functions are never allowed to clear errno, so we have to save |
| 197 | // |
| 198 | class ErrnoSaver { |
| 199 | public: |
| 200 | ErrnoSaver() { fSavedErrno = ::errno; ::errno = 0; } |
| 201 | ~ErrnoSaver() { if (!::errno) ::errno = fSavedErrno; } |
| 202 | private: |
| 203 | int fSavedErrno; |
| 204 | }; |
| 205 | |
| 206 | #define SAVE_AND_CLEAR_ERRNO ErrnoSaver saveErrno |
| 207 | |
| 208 | class SocketTable; |
| 209 | |
| 210 | #if PRAGMA_ALIGN_SUPPORTED |
| 211 | #pragma options align=mac68k |
| 212 | #endif |
| 213 | |
| 214 | class Socket { |
| 215 | friend class SocketTable; |
| 216 | |
| 217 | short refCount; |
| 218 | protected: |
| 219 | Socket(); |
| 220 | public: |
| 221 | virtual int bind(void * name, int namelen); |
| 222 | virtual int connect(void * address, int addrlen); |
| 223 | virtual int listen(int qlen); |
| 224 | virtual Socket * accept(void * address, int * addrlen); |
| 225 | virtual int read(void * buffer, int buflen); |
| 226 | virtual int write(void * buffer, int buflen); |
| 227 | virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen); |
| 228 | virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen); |
| 229 | virtual int getsockname(void * name, int * namelen); |
| 230 | virtual int getpeername(void * name, int * namelen); |
| 231 | virtual int getsockopt(int level, int optname, void *optval, int * optlen); |
| 232 | virtual int setsockopt(int level, int optname, void *optval, int optlen); |
| 233 | virtual int fcntl(unsigned int cmd, int arg); |
| 234 | virtual int ioctl(unsigned int request, void *argp); |
| 235 | virtual int fstat(struct stat * buf); |
| 236 | virtual long lseek(long offset, int whence); |
| 237 | virtual int ftruncate(long offset); |
| 238 | virtual int isatty(); |
| 239 | virtual int shutdown(int how); |
| 240 | virtual void pre_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept); |
| 241 | virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception); |
| 242 | virtual void post_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept); |
| 243 | virtual ~Socket(); |
| 244 | |
| 245 | void operator++() { ++refCount; } |
| 246 | void operator--() { if (!--refCount) delete this; } |
| 247 | }; |
| 248 | |
| 249 | |
| 250 | #if PRAGMA_ALIGN_SUPPORTED |
| 251 | #pragma options align=reset |
| 252 | #endif |
| 253 | |
| 254 | class SocketDomain { |
| 255 | static SocketDomain * domains[GUSI_MAX_DOMAIN]; |
| 256 | static ProcessSerialNumber process; |
| 257 | protected: |
| 258 | SocketDomain(int domain); |
| 259 | virtual ~SocketDomain(); |
| 260 | public: |
| 261 | inline static SocketDomain * Domain(int domain); |
| 262 | static void Ready(); |
| 263 | |
| 264 | // Optionally override the following |
| 265 | |
| 266 | virtual Socket * socket(int type, short protocol); |
| 267 | |
| 268 | // Optionally override the following |
| 269 | |
| 270 | virtual int socketpair(int type, short protocol, Socket * sockets[]); |
| 271 | |
| 272 | // Optionally define the following |
| 273 | |
| 274 | virtual int choose( |
| 275 | int type, |
| 276 | char * prompt, |
| 277 | void * constraint, |
| 278 | int flags, |
| 279 | void * name, |
| 280 | int * namelen); |
| 281 | |
| 282 | // Never override the following |
| 283 | |
| 284 | void DontStrip(); |
| 285 | }; |
| 286 | |
| 287 | class SocketTable { |
| 288 | Socket * sockets[GUSI_MAX_FD]; |
| 289 | Boolean needsConsole; |
| 290 | public: |
| 291 | SocketTable(); |
| 292 | ~SocketTable(); |
| 293 | |
| 294 | void InitConsole(); |
| 295 | int Install(Socket * sock, int start = 0); |
| 296 | int Remove(int fd); |
| 297 | Socket * operator[](int fd); |
| 298 | }; |
| 299 | |
| 300 | struct GUSISuffix { |
| 301 | char suffix[4]; |
| 302 | OSType suffType; |
| 303 | OSType suffCreator; |
| 304 | }; |
| 305 | |
| 306 | #if PRAGMA_ALIGN_SUPPORTED |
| 307 | #pragma options align=mac68k |
| 308 | #endif |
| 309 | |
| 310 | // |
| 311 | // I learned the hard way not to rely on bit field alignments |
| 312 | // |
| 313 | |
| 314 | struct GUSIConfigRsrc { |
| 315 | OSType defaultType; |
| 316 | OSType defaultCreator; |
| 317 | |
| 318 | char autoSpin; |
| 319 | unsigned char flags; |
| 320 | |
| 321 | OSType version; |
| 322 | short numSuffices; |
| 323 | GUSISuffix suffices[1]; |
| 324 | }; |
| 325 | |
| 326 | #if PRAGMA_ALIGN_SUPPORTED |
| 327 | #pragma options align=reset |
| 328 | #endif |
| 329 | |
| 330 | struct GUSIConfiguration { |
| 331 | OSType defaultType; |
| 332 | OSType defaultCreator; |
| 333 | |
| 334 | char autoSpin; |
| 335 | |
| 336 | Boolean noChdir; // Set current directory without chdir() |
| 337 | Boolean accurStat; // Return # of subdirectories + 2 in st_nlink |
| 338 | Boolean hasConsole; // Do we have our own console ? |
| 339 | Boolean noAutoInitGraf; // Never automatically do InitGraf |
| 340 | Boolean sharedOpen; // Open files with shared permissions |
| 341 | Boolean sigPipe; // raise SIGPIPE on write to closed socket |
| 342 | Boolean noAppleEvents; // Don't solicit AppleEvents for MPW tools |
| 343 | Boolean delayConsole; // Do not open console until needed |
| 344 | |
| 345 | OSType version; |
| 346 | short numSuffices; |
| 347 | GUSISuffix * suffices; |
| 348 | |
| 349 | GUSIConfiguration(); |
| 350 | void GUSILoadConfiguration(Handle config); |
| 351 | |
| 352 | void SetDefaultFType(const TFileSpec & name) const; |
| 353 | void DoAutoSpin() const; |
| 354 | void AutoInitGraf() const { if (!noAutoInitGraf) DoAutoInitGraf(); } |
| 355 | void DoAutoInitGraf() const; |
| 356 | Boolean DelayConsole() const; |
| 357 | private: |
| 358 | static Boolean firstTime; |
| 359 | static short we; |
| 360 | }; |
| 361 | |
| 362 | extern GUSIConfiguration GUSIConfig; |
| 363 | extern SocketTable Sockets; |
| 364 | |
| 365 | typedef pascal OSErr (*OSErrInitializer)(); |
| 366 | typedef pascal void (*voidInitializer)(); |
| 367 | |
| 368 | class Feature { |
| 369 | Boolean good; |
| 370 | public: |
| 371 | Feature(unsigned short trapNum, TrapType tTyp); |
| 372 | Feature(OSType type, long value); |
| 373 | Feature(OSType type, long mask, long value); |
| 374 | Feature(const Feature & precondition, OSErrInitializer init); |
| 375 | Feature(OSErrInitializer init); |
| 376 | Feature(const Feature & precondition, voidInitializer init); |
| 377 | Feature(voidInitializer init); |
| 378 | Feature(const Feature & cond1, const Feature & cond2); |
| 379 | |
| 380 | operator void*() const { return (void *) good; } |
| 381 | }; |
| 382 | |
| 383 | extern Feature hasMakeFSSpec; |
| 384 | extern Feature hasAlias; |
| 385 | extern Feature hasNewSF; |
| 386 | extern Feature hasProcessMgr; |
| 387 | extern Feature hasCRM; |
| 388 | extern Feature hasCTB; |
| 389 | extern Feature hasStdNBP; |
| 390 | extern Feature hasCM; |
| 391 | extern Feature hasFT; |
| 392 | extern Feature hasTM; |
| 393 | extern Feature hasPPC; |
| 394 | extern Feature hasRevisedTimeMgr; |
| 395 | |
| 396 | class ScattGath { |
| 397 | Handle scratch; |
| 398 | protected: |
| 399 | void * buf; |
| 400 | int len; |
| 401 | int count; |
| 402 | const struct iovec * io; |
| 403 | |
| 404 | ScattGath(const struct iovec *iov, int cnt); |
| 405 | virtual ~ScattGath(); |
| 406 | public: |
| 407 | void * buffer() { return buf; } |
| 408 | int buflen() { return len; } |
| 409 | int length(int l) { return len = l; } |
| 410 | operator void *() { return buf; } |
| 411 | }; |
| 412 | |
| 413 | class Scatterer : public ScattGath { |
| 414 | public: |
| 415 | Scatterer(const struct iovec *iov, int count); |
| 416 | virtual ~Scatterer(); |
| 417 | }; |
| 418 | |
| 419 | class Gatherer : public ScattGath { |
| 420 | public: |
| 421 | Gatherer(const struct iovec *iov, int count); |
| 422 | virtual ~Gatherer(); |
| 423 | }; |
| 424 | |
| 425 | typedef pascal void (*Deferred)(void *); |
| 426 | |
| 427 | class RingBuffer { |
| 428 | // Valid bytes are between consume and produce |
| 429 | // Free bytes are between produce and consume |
| 430 | // bytes between endbuf-spare and endbuf are neither |
| 431 | Ptr buffer; |
| 432 | Ptr endbuf; |
| 433 | Ptr consume; |
| 434 | Ptr produce; |
| 435 | u_short free; |
| 436 | u_short valid; |
| 437 | u_short spare; |
| 438 | Boolean lock; |
| 439 | Deferred defproc; |
| 440 | void * arg; |
| 441 | |
| 442 | public: |
| 443 | RingBuffer(u_short bufsiz); |
| 444 | ~RingBuffer(); |
| 445 | |
| 446 | Ptr Producer(long & len); // Find continuous memory for producer |
| 447 | Ptr Consumer(long & len); // Find continuous memory for consumer |
| 448 | void Validate(long len); // Validate this, unallocate rest |
| 449 | void Invalidate(long len); |
| 450 | void Produce(Ptr from, long & len);// Allocate, copy & validate |
| 451 | void Consume(Ptr to, long & len); // Copy & invalidate |
| 452 | |
| 453 | long Free() { return free; } |
| 454 | long Valid() { return valid; } |
| 455 | |
| 456 | void Defer() { lock = true; } |
| 457 | void Undefer() { lock = false; if (defproc) defproc(arg);} |
| 458 | Boolean Locked() { return lock; } |
| 459 | void Later(Deferred def, void * ar){ defproc = def; arg = ar; } |
| 460 | |
| 461 | operator void *() { return buffer; } |
| 462 | }; |
| 463 | |
| 464 | Boolean GUSIInterrupt(); |
| 465 | |
| 466 | Boolean CopyIconFamily(short srcResFile, short srcID, short dstResFile, short dstID); |
| 467 | |
| 468 | pascal OSErr PPCInit_P(); |
| 469 | |
| 470 | OSErr AppleTalkIdentity(short & net, short & node); |
| 471 | |
| 472 | void CopyC2PStr(const char * cstr, StringPtr pstr); |
| 473 | |
| 474 | #endif |