OpenTransportNetEvents.c

Go to the documentation of this file.
00001 
00002 /*  $Id: OpenTransportNetEvents.c 1263 2006-04-13 17:37:32Z creecode $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #ifdef NeverDefine_For_Reference
00032 For reference I am listing the error codes from the windows winsock.h file here
00033 
00034 /*
00035  * All Windows Sockets error constants are biased by WSABASEERR from
00036  * the "normal"
00037  */
00038 #define WSABASEERR              10000
00039 /*
00040  * Windows Sockets definitions of regular Microsoft C error constants
00041  */
00042 #define WSAEINTR                (WSABASEERR+4)
00043 #define WSAEBADF                (WSABASEERR+9)
00044 #define WSAEACCES               (WSABASEERR+13)
00045 #define WSAEFAULT               (WSABASEERR+14)
00046 #define WSAEINVAL               (WSABASEERR+22)
00047 #define WSAEMFILE               (WSABASEERR+24)
00048 
00049 /*
00050  * Windows Sockets definitions of regular Berkeley error constants
00051  */
00052 #define WSAEWOULDBLOCK          (WSABASEERR+35)
00053 #define WSAEINPROGRESS          (WSABASEERR+36)
00054 #define WSAEALREADY             (WSABASEERR+37)
00055 #define WSAENOTSOCK             (WSABASEERR+38)
00056 #define WSAEDESTADDRREQ         (WSABASEERR+39)
00057 #define WSAEMSGSIZE             (WSABASEERR+40)
00058 #define WSAEPROTOTYPE           (WSABASEERR+41)
00059 #define WSAENOPROTOOPT          (WSABASEERR+42)
00060 #define WSAEPROTONOSUPPORT      (WSABASEERR+43)
00061 #define WSAESOCKTNOSUPPORT      (WSABASEERR+44)
00062 #define WSAEOPNOTSUPP           (WSABASEERR+45)
00063 #define WSAEPFNOSUPPORT         (WSABASEERR+46)
00064 #define WSAEAFNOSUPPORT         (WSABASEERR+47)
00065 #define WSAEADDRINUSE           (WSABASEERR+48)
00066 #define WSAEADDRNOTAVAIL        (WSABASEERR+49)
00067 #define WSAENETDOWN             (WSABASEERR+50)
00068 #define WSAENETUNREACH          (WSABASEERR+51)
00069 #define WSAENETRESET            (WSABASEERR+52)
00070 #define WSAECONNABORTED         (WSABASEERR+53)
00071 #define WSAECONNRESET           (WSABASEERR+54)
00072 #define WSAENOBUFS              (WSABASEERR+55)
00073 #define WSAEISCONN              (WSABASEERR+56)
00074 #define WSAENOTCONN             (WSABASEERR+57)
00075 #define WSAESHUTDOWN            (WSABASEERR+58)
00076 #define WSAETOOMANYREFS         (WSABASEERR+59)
00077 #define WSAETIMEDOUT            (WSABASEERR+60)
00078 #define WSAECONNREFUSED         (WSABASEERR+61)
00079 #define WSAELOOP                (WSABASEERR+62)
00080 #define WSAENAMETOOLONG         (WSABASEERR+63)
00081 #define WSAEHOSTDOWN            (WSABASEERR+64)
00082 #define WSAEHOSTUNREACH         (WSABASEERR+65)
00083 #define WSAENOTEMPTY            (WSABASEERR+66)
00084 #define WSAEPROCLIM             (WSABASEERR+67)
00085 #define WSAEUSERS               (WSABASEERR+68)
00086 #define WSAEDQUOT               (WSABASEERR+69)
00087 #define WSAESTALE               (WSABASEERR+70)
00088 #define WSAEREMOTE              (WSABASEERR+71)
00089 
00090 #define WSAEDISCON              (WSABASEERR+101)
00091 
00092 /*
00093  * Extended Windows Sockets error constant definitions
00094  */
00095 #define WSASYSNOTREADY          (WSABASEERR+91)
00096 #define WSAVERNOTSUPPORTED      (WSABASEERR+92)
00097 #define WSANOTINITIALISED       (WSABASEERR+93)
00098 
00099 /*
00100  * Error return codes from gethostbyname() and gethostbyaddr()
00101  * (when using the resolver). Note that these errors are
00102  * retrieved via WSAGetLastError() and must therefore follow
00103  * the rules for avoiding clashes with error numbers from
00104  * specific implementations or language run-time systems.
00105  * For this reason the codes are based at WSABASEERR+1001.
00106  * Note also that [WSA]NO_ADDRESS is defined only for
00107  * compatibility purposes.
00108  */
00109 
00110 #define h_errno         WSAGetLastError()
00111 
00112 /* Authoritative Answer: Host not found */
00113 #define WSAHOST_NOT_FOUND       (WSABASEERR+1001)
00114 #define HOST_NOT_FOUND          WSAHOST_NOT_FOUND
00115 
00116 /* Non-Authoritative: Host not found, or SERVERFAIL */
00117 #define WSATRY_AGAIN            (WSABASEERR+1002)
00118 #define TRY_AGAIN               WSATRY_AGAIN
00119 
00120 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
00121 #define WSANO_RECOVERY          (WSABASEERR+1003)
00122 #define NO_RECOVERY             WSANO_RECOVERY
00123 
00124 /* Valid name, no data record of requested type */
00125 #define WSANO_DATA              (WSABASEERR+1004)
00126 #define NO_DATA                 WSANO_DATA
00127 
00128 /* no address, look for MX record */
00129 #define WSANO_ADDRESS           WSANO_DATA
00130 #define NO_ADDRESS              WSANO_ADDRESS
00131 
00132 #endif
00133 //This ends the Reference Section
00134 
00135 
00136 static unsigned char * xtierrorstrings [] = {
00137     BIGSTRING (""),                                                     /* 3149 */
00138     BIGSTRING ("\x1B" "A Bad address was specified"),                   /* 3150 */
00139     BIGSTRING ("\x1A" "A Bad option was specified"),                    /* 3151 */
00140     BIGSTRING ("\x19" "Missing access permission"),                     /* 3152 */
00141     BIGSTRING ("\x16" "Bad provider reference"),                        /* 3153 */
00142     BIGSTRING ("\x18" "No address was specified"),                      /* 3154 */
00143     BIGSTRING ("\x1A" "Call issued in wrong state"),                    /* 3155 */
00144     BIGSTRING ("\x21" "Sequence specified does not exist"),             /* 3156 */
00145     BIGSTRING ("\x17" "A system error occurred"),                       /* 3157 */
00146     BIGSTRING ("\x21" "An event occurred - call OTLook()"),             /* 3158 */
00147     BIGSTRING ("\x27" "An illegal amount of data was specified"),       /* 3159 */
00148     BIGSTRING ("\x1C" "Passed buffer not big enough"),                  /* 3160 */
00149     BIGSTRING ("\x1B" "Provider is flow-controlled"),                   /* 3161 */
00150     BIGSTRING ("\x1D" "No data available for reading"),                 /* 3162 */
00151     BIGSTRING ("\x22" "No disconnect indication available"),            /* 3163 */
00152     BIGSTRING ("\x27" "No Unit Data Error indication available"),       /* 3164 */
00153     BIGSTRING ("\x1D" "A Bad flag value was supplied"),                 /* 3165 */
00154     BIGSTRING ("\x27" "No orderly release indication available"),       /* 3166 */
00155     BIGSTRING ("\x18" "Command is not supported"),                      /* 3167 */
00156     BIGSTRING ("\x23" "State is changing - try again later"),           /* 3168 */
00157     BIGSTRING ("\x28" "Bad structure type requested for OTAlloc"),      /* 3169 */
00158     BIGSTRING ("\x1A" "Host not found (DNS error)"),                    /* 3170 */
00159     BIGSTRING ("\x29" "A Bind to an in-use address with qlen > 0"),     /* 3171 */
00160     BIGSTRING ("\x23" "Address requested is already in use"),           /* 3172 */
00161     BIGSTRING ("\x27" "Accept failed because of pending listen"),       /* 3173 */
00162     BIGSTRING ("\x28" "Tried to accept on incompatible endpoint"),      /* 3174 */
00163     BIGSTRING (""),                                                     /* 3175 */
00164     BIGSTRING (""),                                                     /* 3176 */
00165     BIGSTRING (""),                                                     /* 3177 */
00166     BIGSTRING ("\x26" "An unspecified provider error occurred"),        /* 3178 */
00167     BIGSTRING ("\x24" "A synchronous call at interrupt time"),          /* 3179 */
00168     BIGSTRING ("\x19" "The command was cancelled")                      /* 3180 */
00169     };
00170 
00171 #if 0
00172 
00173 static unsigned char * dnserrorstrings [5] = {
00174     BIGSTRING (""),
00175     BIGSTRING ("\x1b" "Host not found. (DNS error)"),                               /* 1 */
00176     BIGSTRING ("\x37" "Non-authoritative host not found. (Temporary DNS error)"),   /* 2 */
00177     BIGSTRING ("\x22" "Non-recoverable error. (DNS error)"),                        /* 3 */
00178     BIGSTRING ("\x39" "Valid name, no data record of requested type. (DNS error)"), /* 4 */
00179     };
00180     
00181 #endif
00182 
00183 static unsigned char * stdcliberrorstrings [80] = {
00184     BIGSTRING (""),
00185     BIGSTRING ("\x1b" "Permission denied"),                     /* 1 */
00186     BIGSTRING ("\x37" "No such file or directory"),             /* 2 */
00187     BIGSTRING ("\x22" "No such resource"),                      /* 3 */
00188     BIGSTRING ("\x39" "Interrupted system service"),            /* 4 */
00189     BIGSTRING ("\x12" "Input/output error"),                    /* 5 */
00190     BIGSTRING ("\x15" "Device not configured"),                 /* 6 */
00191     BIGSTRING ("\x16" "Argument list too long"),                /* 7 */
00192     BIGSTRING ("\x11" "Exec format error"),                     /* 8 */
00193     BIGSTRING ("\x13" "Bad file descriptor"),                   /* 9 */
00194     BIGSTRING ("\x12" "No child processes"),                    /* 10 */
00195     BIGSTRING ("\x19" "Resource deadlock avoided"),             /* 11 */
00196     BIGSTRING ("\x16" "Cannot allocate memory"),                /* 12 */
00197     BIGSTRING ("\x11" "Permission denied"),                     /* 13 */
00198     BIGSTRING ("\x0b" "Bad address"),                           /* 14 */
00199     BIGSTRING ("\x15" "Block device required"),                 /* 15 */
00200     BIGSTRING ("\x0b" "Device busy"),                           /* 16 */
00201     BIGSTRING ("\x0b" "File exists"),                           /* 17 */
00202     BIGSTRING ("\x11" "Cross-device link"),                     /* 18 */
00203     BIGSTRING ("\x21" "Operation not supported by device"),     /* 19 */
00204     BIGSTRING ("\x0f" "Not a directory"),                       /* 20 */
00205     BIGSTRING ("\x0e" "Is a directory"),                        /* 21 */
00206     BIGSTRING ("\x10" "Invalid argument"),                      /* 22 */
00207     BIGSTRING ("\x1d" "Too many open files in system"),         /* 23 */
00208     BIGSTRING ("\x15" "Too many open sockets"),                 /* 24 */
00209     BIGSTRING ("\x1e" "Inappropriate ioctl for device"),        /* 25 */
00210     BIGSTRING ("\x0e" "Text file busy"),                        /* 26 */
00211     BIGSTRING ("\x0e" "File too large"),                        /* 27 */
00212     BIGSTRING ("\x17" "No space left on device"),               /* 28 */
00213     BIGSTRING ("\x0d" "Illegal seek"),                          /* 29 */
00214     BIGSTRING ("\x15" "Read-only file system"),                 /* 30 */
00215     BIGSTRING ("\x0e" "Too many links"),                        /* 31 */
00216     BIGSTRING ("\x0b" "Broken pipe"),                           /* 32 */
00217     BIGSTRING (""),
00218     BIGSTRING (""),
00219 
00220 /* non-blocking and interrupt i/o */
00221     BIGSTRING ("\x20" "Resource temporarily unavailable"),      /* 35 */
00222 
00223 /* ipc/network software -- argument errors */
00224     BIGSTRING ("\x23" "A blocking operation is in progress"),   /* 36 */
00225     BIGSTRING ("\x20" "Operation is already in progress"),      /* 37 */
00226 
00227 /* ipc/network software -- argument errors */
00228     BIGSTRING ("\x20" "Socket operation on a non-socket"),      /* 38 */
00229     BIGSTRING ("\x1f" "Destination address is required"),       /* 39 */
00230     BIGSTRING ("\x10" "Message too long"),                      /* 40 */
00231     BIGSTRING ("\x1e" "Protocol wrong type for socket"),        /* 41 */
00232     BIGSTRING ("\x16" "Protocol not available"),                /* 42 */
00233     BIGSTRING ("\x16" "Protocol not supported"),                /* 43 */
00234     BIGSTRING ("\x19" "Socket type not supported"),             /* 44 */
00235     BIGSTRING ("\x21" "Operation not supported on socket"),     /* 45 */
00236     BIGSTRING ("\x1d" "Protocol family not supported"),         /* 46 */
00237     BIGSTRING ("\x2f" "Address family not supported by protocol family"),   /* 47 */
00238     BIGSTRING ("\x16" "Address already in use"),                /* 48 */
00239     BIGSTRING ("\x1e" "Can't assign requested address"),        /* 49 */
00240 
00241 /* ipc/network software -- operational errors */
00242     BIGSTRING ("\x0f" "Network is down"),                       /* 50 */
00243     BIGSTRING ("\x16" "Network is unreachable"),                /* 51 */
00244     BIGSTRING ("\x23" "Network dropped connection on reset"),   /* 52 */
00245     BIGSTRING ("\x20" "Software caused connection abort"),      /* 53 */
00246     BIGSTRING ("\x18" "Connection reset by peer"),              /* 54 */
00247     BIGSTRING ("\x19" "No buffer space available"),             /* 55 */
00248     BIGSTRING ("\x1b" "Socket is already connected"),           /* 56 */
00249     BIGSTRING ("\x17" "Socket is not connected"),               /* 57 */
00250     BIGSTRING ("\x20" "Can't send after socket shutdown"),      /* 58 */
00251     BIGSTRING ("\x21" "Too many references: can't splice"),     /* 59 */
00252     BIGSTRING ("\x14" "Connection timed out"),                  /* 60 */
00253     BIGSTRING ("\x12" "Connection refused"),                    /* 61 */
00254 
00255     BIGSTRING ("\x21" "Too many levels of symbolic links"), /* 62 */
00256     BIGSTRING ("\x12" "File name too long"),                /* 63 */
00257 
00258     BIGSTRING ("\x0c" "Host is down"),                      /* 64 */
00259     BIGSTRING ("\x10" "No route to host"),                  /* 65 */
00260     BIGSTRING ("\x13" "Directory not empty"),               /* 66 */
00261     BIGSTRING ("\x12" "Too many processes"),                /* 67 */
00262     BIGSTRING ("\x0e" "Too many users"),                    /* 68 */
00263     BIGSTRING ("\x13" "Disc quota exceeded"),               /* 69 */
00264 
00265 /* Network File System */
00266     BIGSTRING ("\x15" "Stale NFS file handle"),             /* 70 */
00267     BIGSTRING ("\x21" "Too many levels of remote in path"), /* 71 */
00268     BIGSTRING ("\x11" "RPC struct is bad"),                 /* 72 */
00269     BIGSTRING ("\x11" "RPC version wrong"),                 /* 73 */
00270     BIGSTRING ("\x13" "RPC prog. not avail"),               /* 74 */
00271     BIGSTRING ("\x15" "Program version wrong"),             /* 75 */
00272     BIGSTRING ("\x19" "Bad procedure for program"),         /* 76 */
00273     BIGSTRING ("\x12" "No locks available"),                /* 77 */
00274     BIGSTRING ("\x18" "Function not implemented"),          /* 78 */
00275     BIGSTRING ("\x21" "Inappropriate file type or format"), /* 79 */
00276     }; //tcperrorstrings
00277 
00278 #define wsprintf sprintf
00279 
00280 #include "mac.h"
00281 #include "error.h"
00282 #include "kb.h"
00283 #include "ops.h"
00284 #include "memory.h"
00285 #include "threads.h"
00286 #include "strings.h"
00287 #include "lang.h"
00288 #include "langinternal.h"
00289 #include "process.h"
00290 #include "processinternal.h"
00291 #include "shell.h"
00292 #include "shellhooks.h"
00293 #include "timedate.h"
00294 #include "WinSockNetEvents.h"
00295 #include "frontierdebug.h"
00296 #include "file.h"
00297 
00298 
00299 #ifndef OTAssert
00300     #define OTAssert(name, cond)    ((cond) ? ((void) 0) : (DebugStr( __FILE__ ": " #name ": " #cond )))
00301 #endif
00302 
00303 #define NO_HOST_SERVICES NULL
00304 
00305 #define SOCKTYPE_INVALID -1
00306 #define SOCKTYPE_UNKNOWN 0
00307 #define SOCKTYPE_OPEN 1
00308 #define SOCKTYPE_DATA 2
00309 #define SOCKTYPE_LISTENING 3
00310 #define SOCKTYPE_CLOSED 4
00311 #define SOCKTYPE_LISTENSTOPPED 5
00312 #define SOCKTYPE_INACTIVE 6
00313 
00314 #define INTNETERROR_INVALIDSTREAM -1
00315 
00316 static const long kPacketSize = 8192L;
00317 
00318 typedef short tysocktypeid;
00319 
00320 typedef struct tylistenrecord * ListenRecordRef;
00321 
00322 typedef struct tyendpointrecord * EndpointRecordRef;
00323 
00324 typedef struct tyepstatsrecord {
00325     long    cttotal;
00326     long    ctidle;
00327     long    ctbroken;
00328     long    ctworking;
00329     long    ctwaiting;
00330     } tyepstatsrecord;
00331 
00332 /*
00333     2004-10-28 aradke: OTLink and OTLIFO must be aligned on 32-bit boundaries!
00334 */
00335     
00336 typedef struct tylistenrecord {
00337     EndpointRef         ep;
00338     OTLink              validationlink;     /* Link into an OT FIFO (not atomic) */
00339     OTLIFO              idleEPs;            /* Endpoints ready to accept a new incoming connection */
00340     OTLIFO              brokenEPs;          /* Collect failed endpoints for recycling by worker thread */
00341     OTLIFO              readyEPs;           /* Ready to be picked up by the worker thread which will spawn a thread to call the daemon */
00342     OTLIFO              waitingEPs;         /* Endpoints waiting to complete an orderly disconnect */
00343     UInt8               stateflags;
00344     OTConfigurationRef  masterconfig;
00345     EndpointRecordRef   acceptors;
00346     long                maxdepth;
00347     long                refcon;
00348     long                idthread;
00349     hdldatabaserecord   hdatabase;
00350     Handle              hcallbacktree;
00351     tyepstatsrecord     stats;
00352     tysocktypeid        typeID;
00353     boolean             fllistenpending;
00354     bigstring           callback;
00355     } tylistenrecord;
00356 
00357 typedef struct tyendpointrecord {
00358     EndpointRef         ep;
00359     OTLink              link;           /* Used for linking into TCP low-level lists (atomic) */
00360     OTLink              validationlink; /* Used for linking into worker thread lists (atomic) */
00361     UInt8               stateflags;
00362     UInt8               completionflags;
00363     OSStatus            result;
00364     tysocktypeid        typeID;
00365     long                timestamp;      /* System time when we started waiting for an orderly disconnect */
00366     ListenRecordRef     listener;       /* Nil if not operated by a listener */
00367     TCall*              sendCall;       /* Not nil if we initiate a connection */
00368     } tyendpointrecord;
00369 
00370 #if TARGET_API_MAC_CARBON == 1
00371     /*Code change by Timothy Paustian Monday, September 25, 2000 8:34:30 PM
00372     I added these globals to keep the UPPs for carbon.*/
00373     ThreadEntryTPP  gThreadEntryCallback;
00374     OTNotifyUPP     gListenNotifierUPP;
00375     OTListSearchUPP gListSearchUPP;
00376     OTNotifyUPP     gNotifierUPP;
00377     OTListSearchUPP gEndListSearchUPP;
00378     OTNotifyUPP     gDNRNotifierUPP;
00379 #endif
00380 
00381 static tyepstatsrecord epstats;
00382 
00383 static OTList sListenList;      /* List of valid listen streams to verify against when receiving params from scripts */
00384 static OTList sEndpointList;    /* List of valid active streams to verify against when receiving params from scripts */
00385 
00386 static OTLIFO sIdleEPs;         /* Endpoints ready to accept a new incoming connection -- Listeners have their own private list */
00387 static OTLIFO sBrokenEPs;       /* Collect failed endpoints for recycling by main thread -- Listeners have their own private list */
00388 static OTLIFO sWaitingEPs;      /* Endpoints waiting to complete an orderly disconnect */
00389 
00390 static OTConfigurationRef sMasterConfig;
00391 
00392 static OSType sOTVersionSelector = 'otvr';
00393 static long sOTVersion;
00394 
00395 static short frontierWinSockCount = 0;
00396 static boolean frontierWinSockLoaded = false;
00397 
00398 
00399 enum {
00400     kBrokenBit                      = 0, // Bit numbers in stateflags fields
00401     kOpenInProgressBit              = 1,
00402     kPassconBit                     = 2,
00403     kBoundBit                       = 3,
00404     kDontDisposeBit                 = 4,
00405     kWaitingForConnectBit           = 5,
00406     kWaitingForDisconnectBit        = 6,
00407     
00408     kConnectCompleteBit             = 0, // Bit numbers in completionflags fields
00409     kGetProtAddressBit              = 1,
00410     kRcvdDisconnectBit              = 2,
00411     kSntDisconnectBit               = 3,
00412     kRcvdOrderlyDisconnectBit       = 4,
00413     kIPReuseAddrBit                 = 5,
00414     kTCPKeepAliveBit                = 6,
00415     
00416     kOTVersion111   = 0x01110000, // Minimum version of Open Transport required
00417     
00418     kTCPKeepAliveInMinutes              = 1,
00419     kTCPWaitSecsForConnect              = 30, // seconds allowed for connect to complete, when elapsed we return an OT error (-3260 or -3259)
00420 
00421     kTCPWaitSecsForOrderlyDisconnect    = 60, // seconds allowed for orderly disconnect to complete, when elapsed we initiate an abortive disconnect        
00422     
00423     kDontQueueIt                        = 0,
00424     kQueueIt                            = 1
00425     };
00426 
00427 //
00428 //  Option structure 
00429 //  
00430 //  This is used to pass down both IP_REUSEADDR and TCP_KEEPALIVE in the
00431 //  same option message
00432 //
00433 
00434 struct TKeepAliveOpt {
00435     UInt32      len;
00436     OTXTILevel  level;
00437     OTXTIName   name;
00438     UInt32      status;
00439     UInt32      tcpKeepAliveOn;
00440     UInt32      tcpKeepAliveTimer;
00441 };
00442 
00443 typedef struct TKeepAliveOpt TKeepAliveOpt;
00444 
00445 
00446 /* DNS queries structure */
00447 
00448 const unsigned long fcomplete = 1L;
00449 
00450 typedef struct {
00451     OTResult result;
00452     unsigned long flags;
00453     } dnsquery;
00454 
00455 
00456 /* Templates for static functions */
00457 
00458 static void InitEndpoint (EndpointRecordRef epref, EndpointRef ep, ListenRecordRef listenref);
00459 static pascal void ReturnEndpoint (EndpointRecordRef epref, OTResult result, int completionbit);
00460 static boolean CheckEndpointList (EndpointRecordRef epref);
00461 static boolean CheckListenList (ListenRecordRef listenref);
00462 static void CheckUnbind (EndpointRecordRef epref, OTResult result, Boolean queueIt);
00463 static OSStatus DoBind (EndpointRecordRef epref);
00464 static void DoRcvDisconnect (EndpointRecordRef epref);
00465 static void EnterRcvDisconnect (EndpointRecordRef epref);
00466 static void DoListenRcvDisconnect (ListenRecordRef listenref);
00467 static void EnterListenAccept (ListenRecordRef listenref);
00468 static OSStatus DoSndOrderlyDisconnect (EndpointRecordRef epref, boolean flrecurse);
00469 //static OSStatus EnterSndOrderlyDisconnect (EndpointRecordRef epref);
00470 static OSStatus DoSndDisconnect (EndpointRecordRef epref);
00471 static OSStatus EnterSndDisconnect (EndpointRecordRef epref);
00472 static void ReadAllAndClose (EndpointRecordRef epref);
00473 //static void DoWaitList (ListenRecordRef listenref);
00474 static pascal void DNRNotifier (void *context, OTEventCode event, OTResult result, void *cookie);
00475 static pascal void ListenNotifier (void *context, OTEventCode code, OTResult result, void *cookie);
00476 static pascal void Notifier (void *context, OTEventCode code, OTResult result, void *cookie);
00477 static OSStatus EPOpen (EndpointRecordRef epref, OTConfigurationRef cfg);
00478 static boolean EPClose (EndpointRecordRef epref);
00479 static void Recycle (ListenRecordRef listenref);
00480 
00481 /*Code change by Timothy Paustian Monday, September 25, 2000 8:58:07 PM
00482 needed to add a declaration to get the new carbon stuff to compile.*/
00483 static void *fwsacceptingthreadmain (void *param);
00484 
00485 
00486 /* TCPTRACKER stuff */
00487 
00488 static char * TCPGETTYPE (tysocktypeid typeID) {
00489     switch (typeID) {
00490         case SOCKTYPE_INVALID:
00491             return ("INVALID");
00492 
00493         case SOCKTYPE_UNKNOWN:
00494             return ("UNKNOWN");
00495 
00496         case SOCKTYPE_OPEN:
00497             return ("OPEN");
00498 
00499         case SOCKTYPE_DATA:
00500             return ("DATA");
00501 
00502         case SOCKTYPE_LISTENING:
00503             return ("LISTENING");
00504 
00505         case SOCKTYPE_CLOSED:
00506             return ("CLOSED");
00507 
00508         case SOCKTYPE_LISTENSTOPPED:
00509             return ("LISTEN-STOPPED");
00510 
00511         case SOCKTYPE_INACTIVE:
00512             return ("INACTIVE");
00513 
00514         default:
00515             break;
00516         }
00517 
00518     return ("BAD Type value");
00519     } /*TCPGETTYPE*/
00520 
00521 
00522 /*
00523     To disable the tcp tracker, don't define TCPTRACKER.
00524 
00525     To enable tcp tracker ouput in the about window, define TCPTRACKER == 1.
00526 
00527     To enable tcp tracker error ouput to a file, define TCPTRACKER == 2.
00528 
00529     To enable full tcp tracker output to a file, define TCPTRACKER == 3.
00530 */
00531 
00532 //#undef TCPTRACKER
00533 #define TCPTRACKER 1
00534 //#define TCPTRACKER 2
00535 //#define TCPTRACKER 3
00536 
00537 #if (TCPTRACKER == 3)
00538 #pragma message ("*********************** TCPTRACKER is ON: Full output to tcpfile.txt ***********************")
00539 
00540 static boolean fllogger = true;
00541 
00542 #ifdef WIN95VERSION
00543 extern  DWORD ixthreadglobalsgrabcount;         // Tls index of counter for nest globals grabbing
00544 #endif
00545 
00546 static FILE * tcpfile = NULL;
00547 static char TCPmsg[400];
00548 
00549 #define TCPprintf(msg) msg
00550 #define TCPERRORprintf(msg) msg
00551 
00552 static void TCPWRITEMSG () {
00553     unsigned long ticks = gettickcount ();
00554     static unsigned long lastticks = 0;
00555     #ifdef WIN95VERSION
00556         DWORD idthread;
00557         static DWORD idlastthread = 0;
00558         long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
00559     #endif
00560     #ifdef MACVERSION
00561         static ThreadID idlastthread = 0;
00562         ThreadID idthread;
00563     #endif
00564     
00565     if (fllogger) {
00566         if (tcpfile == NULL) {
00567             tcpfile = fopen ("tcpfile.txt", "w+");
00568             }
00569         #ifdef WIN95VERSION
00570             idthread = GetCurrentThreadId();
00571         #endif
00572         #ifdef MACVERSION
00573             MacGetCurrentThread (&idthread);
00574         #endif
00575 
00576         if (idthread != idlastthread) {
00577             fprintf (tcpfile, "\n");
00578             idlastthread = idthread;
00579             }
00580 
00581     #ifdef WIN95VERSION
00582         fprintf (tcpfile, "%08X (%04ld) | %04X (%02ld) | %s\n", (unsigned long) ticks, (ticks - lastticks), idthread, grabcount, TCPmsg);
00583     #endif
00584 
00585     #ifdef MACVERSION
00586         fprintf (tcpfile, "%08X (%04ld) | %04X | %s\n", (unsigned long) ticks, (ticks - lastticks), idthread, TCPmsg);
00587     #endif
00588 
00589         lastticks = ticks;
00590 
00591         fflush (tcpfile);
00592         }
00593     } /*TCPWRITEMSG*/
00594 
00595 #define TCPERRORWRITEMSG TCPWRITEMSG
00596 
00597 static void TCPTRACKERCLOSE () {
00598     if (fllogger) {
00599         if (tcpfile != NULL)
00600             fclose (tcpfile);
00601         }
00602     }
00603 
00604 
00605 #elif (TCPTRACKER == 2)
00606 #pragma message ("*********************** TCPTRACKER is ON: Error output to tcpfile.txt **********************")
00607 
00608 static boolean fllogger = true;
00609 
00610 #ifdef WIN95VERSION
00611 extern  DWORD ixthreadglobalsgrabcount;         // Tls index of counter for nest globals grabbing
00612 #endif
00613 
00614 static FILE * tcpfile = NULL;
00615 static char TCPmsg[400];
00616 
00617 #define TCPprintf(msg)
00618 #define TCPWRITEMSG()
00619 
00620 #define TCPERRORprintf(msg) msg
00621 
00622 static void TCPERRORWRITEMSG () {
00623     unsigned long ticks = gettickcount ();
00624     static unsigned long lastticks = 0;
00625     #ifdef WIN95VERSION
00626         DWORD idthread;
00627         static DWORD idlastthread = 0;
00628         long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
00629     #endif
00630     #ifdef MACVERSION
00631         long idthread = (long) (**getcurrentthread ()).idthread;
00632         static long idlastthread = 0;
00633     #endif
00634     
00635     if (fllogger) {
00636     #ifdef WIN95VERSION
00637         idthread = GetCurrentThreadId();
00638     #endif
00639 
00640         if (tcpfile == NULL) {
00641             tcpfile = fopen ("tcpfile.txt", "w+");
00642             }
00643 
00644         if (idthread != idlastthread) {
00645             fprintf (tcpfile, "\n");
00646             idlastthread = idthread;
00647             }
00648 
00649     #ifdef WIN95VERSION
00650         fprintf (tcpfile, "%08X (%04ld) | %04X (%02ld) | %s\n", (unsigned long) ticks, (ticks - lastticks), idthread, grabcount, TCPmsg);
00651     #endif
00652 
00653     #ifdef MACVERSION
00654         fprintf (tcpfile, "%08X (%04ld) | %04X | %s\n", (unsigned long) ticks, (ticks - lastticks), idthread, TCPmsg);
00655     #endif
00656 
00657         lastticks = ticks;
00658 
00659         fflush (tcpfile);
00660         }
00661     } /*TCPWRITEMSG*/
00662 
00663 
00664 static void TCPTRACKERCLOSE () {
00665     if (fllogger) {
00666         if (tcpfile != NULL)
00667             fclose (tcpfile);
00668         }
00669     }
00670 
00671 #elif (TCPTRACKER == 1)
00672 #pragma message ("*********************** TCPTRACKER is ON: Full output to About window **********************")
00673 
00674 #include "about.h"
00675 #define fllogger (aboutstatsshowing())
00676 #define TCPprintf(msg) msg
00677 #define TCPERRORprintf(msg) msg
00678 
00679 static char TCPmsg[400];
00680 
00681 static void TCPWRITEMSG () {
00682     
00683     if (fllogger) {
00684         
00685         convertcstring (BIGSTRING (TCPmsg));
00686         
00687         aboutsetmiscstring ( BIGSTRING (TCPmsg));
00688         }
00689     } /*TCPWRITEMSG*/
00690 
00691 #define TCPERRORWRITEMSG TCPWRITEMSG
00692 
00693 #define TCPTRACKERCLOSE()
00694 
00695 #else
00696 
00697 #define TCPprintf(msg)
00698 #define TCPERRORprintf(msg)
00699 #define TCPWRITEMSG()
00700 #define TCPERRORWRITEMSG()
00701 #define TCPTRACKERIN(functionName, linenumber, streamID)
00702 #define TCPTRACKEROUT(functionName, linenumber, streamID)
00703 #define TCPTRACKERCLOSE()
00704 
00705 #endif
00706 
00707 #if (defined (TCPTRACKER) && (TCPTRACKER==1 || TCPTRACKER==3))
00708 
00709 static void TCPTRACKERIN (char * functionName, int linenumber, EndpointRecordRef epref, ListenRecordRef listenref) {
00710     if (fllogger) {
00711     
00712         if (epref) {
00713             if (!CheckEndpointList (epref)) {
00714                 wsprintf (TCPmsg, "Entering %s at line %d, EndpointRecordRef = %08lx - INVALID ENPOINT.", functionName, linenumber, (long) epref);
00715                 TCPWRITEMSG ();
00716                 return;
00717                 }
00718 
00719             wsprintf (TCPmsg, "Entering %s at line %d, EndpointRecordRef = %08lx, Endpoint = %08lx, Type = %s, State Flags = %02x, Completion Flags = %02x, Listen Ref = %08lX.",
00720                 functionName, linenumber, (long) epref, (long) epref->ep, TCPGETTYPE (epref->typeID), epref->stateflags, epref->completionflags, (long) epref->listener);
00721         
00722             TCPWRITEMSG ();
00723             }
00724 
00725         if (listenref) {
00726             if (!CheckListenList (listenref)) {
00727                 wsprintf (TCPmsg, "Entering %s at line %d, ListenRecordRef = %08lx - INVALID ENPOINT.", functionName, linenumber, (long) listenref);
00728                 TCPWRITEMSG ();
00729                 return;
00730                 }
00731 
00732             wsprintf (TCPmsg, "Entering %s at line %d, ListenRecordRef = %08lx, Endpoint = %08lx, Type = %s, Max Depth = %ld, Refcon = %08lX, Thread = %ld",
00733                 functionName, linenumber, (long) listenref, (long) listenref->ep, TCPGETTYPE (listenref->typeID), listenref->maxdepth, listenref->refcon, listenref->idthread);
00734         
00735             TCPWRITEMSG ();
00736             }
00737         }
00738     } /*TCPTRACKERIN*/
00739 
00740 
00741 static void TCPTRACKEROUT (char * functionName, int linenumber, EndpointRecordRef epref, ListenRecordRef listenref) {
00742     if (fllogger) {
00743     
00744         if (epref) {
00745             if (!CheckEndpointList (epref)) {
00746                 wsprintf (TCPmsg, "Exiting %s at line %d, EndpointRecordRef = %08lx - INVALID ENPOINT.", functionName, linenumber, (long) epref);
00747                 TCPWRITEMSG ();
00748                 return;
00749                 }
00750 
00751             wsprintf (TCPmsg, "Exiting %s at line %d, EndpointRecordRef = %08lx, Endpoint = %08lx, Type = %s, State Flags = %02x, Completion Flags = %02x, Listen Ref = %08lX.",
00752                 functionName, linenumber, (long) epref, (long) epref->ep, TCPGETTYPE (epref->typeID), epref->stateflags, epref->completionflags, (long) epref->listener);
00753         
00754             TCPWRITEMSG ();
00755             }
00756 
00757         if (listenref) {
00758             if (!CheckListenList (listenref)) {
00759                 wsprintf (TCPmsg, "Exiting %s at line %d, ListenRecordRef = %08lx - INVALID ENPOINT.", functionName, linenumber, (long) listenref);
00760                 TCPWRITEMSG ();
00761                 return;
00762                 }
00763 
00764             wsprintf (TCPmsg, "Exiting %s at line %d, ListenRecordRef = %08lx, Endpoint = %08lx, Type = %s, Max Depth = %ld, Refcon = %08lX, Thread = %ld",
00765                 functionName, linenumber, (long) listenref, (long) listenref->ep, TCPGETTYPE (listenref->typeID), listenref->maxdepth, listenref->refcon, listenref->idthread);
00766         
00767             TCPWRITEMSG ();
00768             }
00769         }
00770     } /*TCPTRACKEROUT*/
00771 
00772 #else
00773 
00774 #define TCPTRACKERIN(functionName, linenumber, epref, listenref)
00775 #define TCPTRACKEROUT(functionName, linenumber, epref, listenref)
00776 
00777 #endif
00778 
00779 
00780 #ifdef PIKE /*7.1b3 PBS: maxconnections is now variable.*/
00781 
00782     /*extern const*/ /*long maxconnections = 5;*/
00783     
00784     long maxconnections = longinfinity; /*7.1b5 PBS: no more connection limit*/
00785 
00786 #else
00787 
00788     /*extern const*/ long maxconnections = longinfinity; /*7.0b37 PBS: reported in system.environment table in Frontier*/
00789 
00790 #endif
00791 
00792 static long ctconnections = 0;
00793 
00794 
00795 long fwsNetEventGetConnectionCount (void) {
00796 
00797     /*7.0b37 PBS: return current count of TCP connections.
00798     Used by tcp.countConnections verb.
00799     */
00800 
00801     return (ctconnections);
00802     } /*fwsNetEventGetConnectionCount*/
00803 
00804 
00805 static boolean incrementconnectioncounter (void) {
00806 
00807     if (ctconnections >= maxconnections)
00808         return (false);
00809 
00810     ctconnections++;
00811 
00812     return (true);  
00813     }/*incrementconnectioncounter*/
00814 
00815 static void decrementconnectioncounter (void) {
00816     
00817     ctconnections--;
00818     
00819     if (ctconnections < 0)  /*7.0b53 PBS: a script can abort or close a stream multiple times.*/
00820                             /*Instead we should get this info from the OS, but until then we do this.*/
00821         ctconnections = 0;
00822 
00823     //assert (ctconnections >= 0);
00824 
00825     }/*decrementconnectioncounter*/
00826     
00827 
00828 
00829 //#else
00830 //  #define incrementconnectioncounter() (true)
00831 //  #define decrementconnectioncounter() ((void *)0L);
00832 //#endif
00833 
00834 
00835 static pascal boolean listendatabasevisit (const void* ref, OTLink* linkToCheck) {
00836     
00837     hdldatabaserecord hdatabase = (hdldatabaserecord) ref;
00838 
00839     return (hdatabase == (OTGetLinkObject (linkToCheck, tylistenrecord, validationlink))->hdatabase);
00840     }/*listendatabasevisit*/
00841 
00842 
00843 static pascal boolean listenlinkvisit (const void* ref, OTLink* linkToCheck) {
00844     
00845     ListenRecordRef listenref = (ListenRecordRef) ref;
00846 
00847     return (listenref == OTGetLinkObject (linkToCheck, tylistenrecord, validationlink));
00848     }/*listenlinkvisit*/
00849 
00850 
00851 static pascal boolean endpointlinkvisit (const void* ref, OTLink* linkToCheck) {
00852     
00853     EndpointRecordRef epref = (EndpointRecordRef) ref;
00854 
00855     return (epref == OTGetLinkObject (linkToCheck, tyendpointrecord, validationlink));
00856     }/*endpointlinkvisit*/
00857 
00858 
00859 static boolean CheckEndpointList (EndpointRecordRef epref) {
00860     
00861     OTLink *eplink;
00862     
00863     #if TARGET_API_MAC_CARBON == 1
00864         eplink = OTFindLink (&sEndpointList, gEndListSearchUPP, (void *) epref);
00865     #else
00866         eplink = OTFindLink (&sEndpointList, &endpointlinkvisit, (void *) epref);
00867     #endif
00868     
00869     return (nil != eplink);
00870     }/*CheckEndpointList*/
00871 
00872 
00873 static boolean CheckListenList (ListenRecordRef listenref) {
00874     
00875     OTLink *listenlink;
00876     
00877     #if TARGET_API_MAC_CARBON == 1
00878         listenlink = OTFindLink (&sListenList, gListSearchUPP, (void *) listenref);
00879     #else
00880         listenlink = OTFindLink (&sListenList, &listenlinkvisit, (void *) listenref);
00881     #endif
00882     
00883     return (nil != listenlink);
00884     }/*CheckListenList*/
00885 
00886 
00887 static void InitEndpoint (EndpointRecordRef epref, EndpointRef ep, ListenRecordRef listenref) {
00888     
00889     OTMemzero (epref, sizeof (tyendpointrecord));
00890     
00891     epref->ep = ep;
00892     
00893     epref->listener = listenref;
00894     
00895     epref->typeID = SOCKTYPE_INVALID;
00896 
00897     return;
00898     }/*InitEndpoint*/
00899 
00900 
00901 static pascal void ReturnEndpoint (EndpointRecordRef epref, OTResult result, int completionbit) {
00902 
00903     if (OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)) {
00904 
00905         epref->result = result;
00906 
00907         OTAtomicClearBit (&epref->stateflags, kWaitingForConnectBit);
00908 
00909         OTAtomicSetBit (&epref->completionflags, completionbit);
00910         }
00911     else {
00912         boolean flbound = OTAtomicTestBit (&epref->stateflags, kBoundBit);
00913         
00914         if (flbound)
00915             result = OTUnbind (epref->ep);
00916         
00917         CheckUnbind (epref, result, !flbound);
00918         }
00919     }/*ReturnEndpoint*/
00920 
00921 
00922 //
00923 //  CheckUnbind
00924 //
00925 //  This routine checks the results of an unbind.   Due to various problems
00926 //  in OpenTransport, an OTUnbind can fail for a number of reasons.  This problem
00927 //  is timing related so you usually won't hit it.   When an OTUnbind fails,
00928 //  we assume the best way to recover is to throw the endpoint on the broken
00929 //  list to be recycled.   Later, in the recycle routine, it will be closed
00930 //  and a new endpoint will be opened to replace it.  If the OTUnbind is
00931 //  successful, the endpoint is put back on the free list to be reused.
00932 //
00933 //  Since the unbind failure is timing related, a more efficient solution
00934 //  would probably be to wait and retry the unbind in a few seconds, 
00935 //  expecting that the call would not fail on the next try.
00936 //
00937 static void CheckUnbind (EndpointRecordRef epref, OTResult result, Boolean queueIt) {
00938     
00939     ListenRecordRef listenref = epref->listener;
00940 
00941     if (kOTNoError != result) {
00942     
00943         if (0 == OTAtomicSetBit (&epref->stateflags, kBrokenBit)) {
00944             /*
00945             The OTAtomicSetBit guarantee's that the EPInfo won't be
00946             enqueued twice.   We only enqueue the EPInfo if the previous
00947             state of the bit was 0.
00948             */
00949             if (nil != listenref) {
00950 
00951                 OTLIFOEnqueue (&listenref->brokenEPs, &epref->link);
00952                 
00953                 listenref->stats.ctworking--;
00954                 
00955                 listenref->stats.ctbroken++;
00956                 }
00957             else {
00958             
00959                 OTLIFOEnqueue (&sBrokenEPs, &epref->link);
00960                 
00961                 epstats.ctworking--;
00962                 
00963                 epstats.ctbroken++;
00964                 }
00965             }
00966         }
00967     else {
00968         if (queueIt) {
00969             
00970             TCP_ASSERT_1 (nil != epref->ep);
00971         
00972             if (nil != listenref) {
00973         
00974                 OTLIFOEnqueue (&listenref->idleEPs, &epref->link);
00975                 
00976                 listenref->stats.ctworking--;
00977                 
00978                 listenref->stats.ctidle++;
00979                 
00980                 if (listenref->fllistenpending)
00981                     EnterListenAccept (listenref);
00982                 }
00983             else {
00984             
00985                 #if TARGET_API_MAC_CARBON == 1
00986                 
00987                     EPClose (epref);
00988                     
00989                     epstats.ctworking--;
00990                     
00991                 #else
00992             
00993                     OTLIFOEnqueue (&sIdleEPs, &epref->link);
00994                 
00995                     epstats.ctworking--;
00996                 
00997                     epstats.ctidle++;
00998                 #endif
00999                 }
01000             }
01001         }
01002     }/*CheckUnbind*/
01003 
01004 
01005 //
01006 //  DoBind
01007 //
01008 //  This routine requests a wildcard port binding from the transport protocol.
01009 //  Since the program doesn't care what port is returned, it passes in NULL
01010 //  for the bind return parameter.  The bind request structure is ephemeral
01011 //  and can be a local stack variable since OT is done with it when the call returns.
01012 //  The bind is done when the notifier receives a T_BINDCOMPLETE event.
01013 //
01014 static OSStatus DoBind (EndpointRecordRef epref) {
01015 
01016     OSStatus err;
01017     TBind bindReq;
01018     InetAddress inAddr;
01019     
01020     /*
01021     Bind the endpoint to a wildcard address (assign us a port, we don't care which one).
01022     */
01023     OTInitInetAddress(&inAddr, 0, 0);
01024     
01025     bindReq.addr.len = sizeof (InetAddress);
01026     bindReq.addr.buf = (unsigned char *) &inAddr;
01027     bindReq.qlen = 0;
01028     
01029     err = OTBind (epref->ep, &bindReq, NULL);
01030     
01031     if (err != kOTNoError)
01032         TCP_MSG_1 ("DoBind: OTBind returned an error");
01033 
01034     return (err);
01035     }/*DoBind*/
01036 
01037 
01038 static OSStatus EnterBind (EndpointRecordRef epref) {
01039 
01040     OSStatus err;
01041     boolean doLeave = OTEnterNotifier (epref->ep);
01042 
01043     err = DoBind (epref);
01044 
01045     if (doLeave)
01046         OTLeaveNotifier (epref->ep);
01047     
01048     return (err);
01049     }/*EnterBind*/
01050 
01051 
01052 static void DoRcvOrderlyDisconnect (EndpointRecordRef epref) {
01053 
01054     OSStatus err;
01055     
01056     err = OTRcvOrderlyDisconnect (epref->ep);
01057     
01058     if (kOTNoError != err)
01059         return;
01060     
01061     OTAtomicSetBit (&epref->completionflags, kRcvdOrderlyDisconnectBit);
01062     
01063     if (!OTAtomicTestBit (&epref->stateflags, kDontDisposeBit))
01064         if (T_IDLE == OTGetEndpointState (epref->ep))
01065             CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
01066     }/*DoRcvOrderlyDisconnect*/
01067 
01068 
01069 static void EnterRcvOrderlyDisconnect (EndpointRecordRef epref) {
01070 
01071     boolean doLeave = OTEnterNotifier (epref->ep);
01072     
01073     DoRcvOrderlyDisconnect (epref);
01074     
01075     if (doLeave)
01076         OTLeaveNotifier (epref->ep);
01077     }/*EnterRcvOrderlyDisconnect*/
01078 
01079 
01080 
01081 static void DoRcvDisconnect (EndpointRecordRef epref) {
01082 
01083     OSStatus err;
01084     TDiscon discon;
01085     
01086     discon.udata.len = nil;
01087     
01088     err = OTRcvDisconnect (epref->ep, &discon);
01089     
01090     
01091     switch (err) {
01092     
01093         case kOTNoError:
01094             epref->result = E2OSStatus (discon.reason);
01095             OTAtomicSetBit (&epref->completionflags, kRcvdDisconnectBit);
01096             break;
01097         
01098         case kOTBufferOverflowErr:
01099             epref->result = kECONNREFUSEDErr; /*most likely cause*/
01100             OTAtomicSetBit (&epref->completionflags, kRcvdDisconnectBit);
01101             break;
01102         
01103         default:
01104             if (err != kOTNoDisconnectErr)
01105                 TCP_MSG_1 ("DoRcvDisconnect: OTRcvDisconnect on endpoint returned an error");
01106             epref->result = err;
01107             break;  
01108         }
01109         
01110     if (!OTAtomicTestBit (&epref->stateflags, kDontDisposeBit))
01111         CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
01112     }/*DoRcvDisconnect*/
01113 
01114 
01115 static void EnterRcvDisconnect (EndpointRecordRef epref) {
01116 
01117     boolean doLeave = OTEnterNotifier (epref->ep);
01118     
01119     DoRcvDisconnect (epref);
01120     
01121     if (doLeave)
01122         OTLeaveNotifier (epref->ep);
01123     }/*EnterRcvDisconnect*/
01124 
01125 
01126 //
01127 //  DoListenRcvDisconnect
01128 //
01129 //  This routine is called from ListenNotifier in T_LISTEN handling
01130 //  upon getting a kOTLookErr back indicating a T_DISCONNECT needs to be handled.
01131 //
01132 static void DoListenRcvDisconnect (ListenRecordRef listenref) {
01133 
01134     OSStatus err;
01135     
01136     err = OTRcvDisconnect (listenref->ep, NULL);
01137     
01138     if (kOTNoError != err)
01139         TCP_MSG_1 ("DoListenRcvDisconnect: OTRcvDisconnect on listener returned an error");
01140     
01141     return;
01142     }/*DoListenRcvDisconnect*/
01143 
01144 
01145 //
01146 //  DoListenAccept
01147 //
01148 //  The handling of a T_LISTEN is greatly simplified by use
01149 //  of the tilisten module, which serializes inbound connections.
01150 //  This means that when doing an OTAccept we won't get a kOTLookErr
01151 //  because another inbound connection arrived and created a T_LISTEN.
01152 //  Without the tilisten module, we have to use the "8 step 
01153 //  listen/accept/disconnect method", which is documented elsewhere.
01154 //  At this point, if we have a free endpoint, accept the connection.
01155 //  If we don't, assume we are overloaded and reject the connection.
01156 //
01157 //  When we are called from inside the notifier due to a T_LISTEN, 
01158 //  DoListenAccept() is called directly.
01159 //
01160 //  When we restart delayed handling of a T_LISTEN, either because of
01161 //  doing a throttle-back or because the program ran out of free endpoints,
01162 //  EnterListenAccept() is called for synchronization on the listener endpoint.
01163 //
01164 
01165 static void DoListenAccept (ListenRecordRef listenref) {
01166 
01167     OTLink* acceptor_link;
01168     EndpointRecordRef acceptor;
01169     TCall call;
01170     InetAddress clientaddr;
01171     OTResult lookResult;
01172     OSStatus err;
01173     
01174 /*  if (!incrementconnectioncounter ()) {
01175         OTSndDisconnect (listenref->ep, nil); /%6.2b13 AR: reject connection (PIKE) %/
01176         return;
01177         }*/
01178     
01179     if (!incrementconnectioncounter ()) {
01180         
01181         listenref->fllistenpending = true;
01182         
01183         return; 
01184         } /*if*/
01185 
01186     //
01187     //  Get an EPInfo & endpoint.   If none are available, defer handling the T_LISTEN.
01188     //
01189     acceptor_link = OTLIFODequeue (&listenref->idleEPs);
01190     
01191     if (acceptor_link == NULL) {
01192         decrementconnectioncounter();
01193         listenref->fllistenpending = true;
01194         return;
01195         }
01196     
01197     listenref->fllistenpending = false;
01198 
01199     listenref->stats.ctidle--;
01200     
01201     listenref->stats.ctworking++;
01202     
01203     acceptor = OTGetLinkObject (acceptor_link, tyendpointrecord, link);
01204     
01205     InitEndpoint (acceptor, acceptor->ep, listenref);
01206         
01207     call.addr.maxlen = sizeof(InetAddress);
01208     call.addr.buf = (unsigned char*) &clientaddr;
01209     call.opt.maxlen = 0;
01210     call.opt.buf = NULL;
01211     call.udata.maxlen = 0;
01212     call.udata.buf = NULL;
01213         
01214     err = OTListen (listenref->ep, &call);
01215 
01216     if (kOTNoError != err) {
01217         //
01218         //  Only two errors are expected at this point.
01219         //  One would be a kOTNoDataErr, indicating the inbound connection
01220         //  was unavailable, temporarily hidden by a higher priority streams
01221         //  message, etc.   The more likely error is a kOTLookErr, 
01222         //  which indicates a T_DISCONNECT on the OTLook()
01223         //  happens when the call we were going to process disconnected.
01224         //  In that case, go away and wait for the next T_LISTEN event.
01225         //
01226         OTLIFOEnqueue (&listenref->idleEPs, &acceptor->link);
01227         
01228         listenref->stats.ctworking--;
01229         
01230         listenref->stats.ctidle++;
01231 
01232         if (kOTNoDataErr != err) {
01233             lookResult = OTLook (listenref->ep);
01234             
01235             if (kOTLookErr == err && T_DISCONNECT == lookResult)
01236                 DoListenRcvDisconnect (listenref);
01237             else    
01238                 TCP_MSG_1 ("Notifier: T_LISTEN - OTListen returned an error");
01239             }
01240                         
01241         decrementconnectioncounter();
01242         
01243         return; 
01244         }
01245     
01246     err = OTAccept (listenref->ep, acceptor->ep, &call);
01247     
01248     if (kOTNoError != err) {
01249         //
01250         //  Again, we have to be able to handle the connection being disconnected
01251         //  while we were trying to accept it.
01252         //
01253         OTLIFOEnqueue (&listenref->idleEPs, &acceptor->link);
01254         
01255         listenref->stats.ctworking--;
01256         
01257         listenref->stats.ctidle++;
01258         
01259         lookResult = OTLook (listenref->ep);
01260         
01261         if (kOTLookErr == err && T_DISCONNECT == lookResult)
01262             DoListenRcvDisconnect (listenref);
01263         else
01264             TCP_MSG_1 ("Notifier: T_LISTEN - OTAccept returned an error");
01265 
01266         decrementconnectioncounter();
01267         }
01268     }/*DoListenAcceept*/
01269 
01270 
01271 //
01272 //  EnterListenAccept
01273 //
01274 //  This is a front end to DoListenAccept() which is used whenever 
01275 //  it is not being called from inside the listener endpoint's notifier.
01276 //  We do this for synchronization.   If we were processing an OTListen()
01277 //  or an OTAccept() and we were interrupted at the listener endpoint's
01278 //  notifier with a T_LISTEN, etc, it would be inconvenient and would require
01279 //  some more sophisticated synchronization code to deal with the problem.
01280 //  The easy way to avoid this is to do an OTEnterNotifier() on the listener's
01281 //  endpoint.   
01282 //
01283 //  Important note - doing OTEnterNotifier on one endpoint only prevents that
01284 //  endpoint's notifier for interrupting us.   Since the same notifier code
01285 //  is used for lots of endpoints here, remember that the one endpoint's 
01286 //  notifier can interrupt another.   Doing an OTEnterNotifier() on the
01287 //  listener endpoint prevents the listener from interrupting us, but it
01288 //  does not prevent the Notifier() routine from interrupting us via 
01289 //  another endpoint which also uses the same routine.
01290 //
01291 //  Important note #2 - Don't ever do an OTEnterNotifier on an acceptor endpoint
01292 //  before doing the OTAccept().   This confuses OT and creates problems.
01293 //
01294 static void EnterListenAccept (ListenRecordRef listenref) {
01295 
01296     boolean doLeave = OTEnterNotifier (listenref->ep);
01297     
01298     DoListenAccept (listenref);
01299 
01300     if (doLeave)
01301         OTLeaveNotifier(listenref->ep);
01302     }
01303 
01304 
01305 //
01306 //  DoSndOrderlyDisconnect
01307 //
01308 //  This routine is a front end to OTSndOrderlyDisconnect(). It's only called
01309 //  from fwsNetEventCloseStream but not from the Notifier.
01310 //
01311 static OSStatus DoSndOrderlyDisconnect (EndpointRecordRef epref, boolean flrecurse) {
01312 
01313     OSStatus err;
01314 
01315     /* Indicate to the notifier that it's now responsible for recycling this endpoint */
01316 
01317     err = OTSndOrderlyDisconnect (epref->ep);
01318     
01319     if (kOTNoError != err) {
01320         
01321         if (kOTLookErr == err) {
01322             
01323             OTResult result = OTLook (epref->ep);
01324             
01325             switch (result) {
01326                 
01327                 case T_DISCONNECT:
01328                     DoRcvDisconnect (epref);
01329                     break;
01330                 
01331                 case T_ORDREL:
01332                     DoRcvOrderlyDisconnect (epref);
01333                     if (flrecurse)
01334                         err = DoSndOrderlyDisconnect (epref, false); // try again, but only once
01335                     break;
01336                 
01337                 default: {
01338                     TCP_MSG_1 ("DoSndOrderlyDisconnect: OTLook returned an unhandled event");
01339                     CheckUnbind (epref, kOTLookErr, kDontQueueIt);
01340                     }
01341                 }
01342             }
01343         else {
01344             TCP_MSG_1 ("DoSndOrderlyDisconnect: OTSndOrderlyDisconnect returned an error");
01345             CheckUnbind (epref, err, kDontQueueIt);
01346             }
01347         }
01348     else
01349         ReadAllAndClose (epref);
01350 
01351     return (err);
01352     }/*DoSndOrderlyDisconnect*/
01353 
01354 #if 0
01355 
01356 static OSStatus EnterSndOrderlyDisconnect (EndpointRecordRef epref) {
01357 
01358     OSStatus err;
01359     boolean doLeave = OTEnterNotifier (epref->ep);
01360 
01361     err = DoSndOrderlyDisconnect (epref);
01362         
01363     if (doLeave)
01364         OTLeaveNotifier(epref->ep);
01365 
01366     return (err);
01367     }/*EnterSndOrderlyDisconnect*/
01368 
01369 #endif
01370 
01371 //
01372 //  DoSndDisconnect
01373 //
01374 //  This routine is a front end to OTSndDisconnect().  It's only called from
01375 //  EnterSndDisconnect and DoSndOrderlyDisconnect but not from the Notifier.
01376 //  We give up control of the endpoint at this point.  The Notifier is supposed to do the clean up.
01377 //
01378 static OSStatus DoSndDisconnect (EndpointRecordRef epref) {
01379 
01380     OSStatus err;
01381 
01382     /* Indicate to the notifier that it's now responsible for recycling this endpoint */
01383     
01384     OTAtomicClearBit (&epref->stateflags, kDontDisposeBit);
01385     
01386     /* Initiate disconnect */
01387 
01388     err = OTSndDisconnect (epref->ep, nil);
01389     
01390     if (kOTNoError != err) {
01391     
01392         if (kOTLookErr == err) {
01393             
01394             OTResult result = OTLook (epref->ep);
01395             
01396             switch (result) {
01397                 
01398                 case T_DISCONNECT:
01399                     DoRcvDisconnect (epref);
01400                     break;
01401                 
01402                 default:
01403                     TCP_MSG_1 ("DoSndDisconnect: OTLook returned an unhandled event");
01404                     CheckUnbind (epref, kOTLookErr, kDontQueueIt);
01405                     break;
01406                 }
01407             }
01408         else {
01409             CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
01410             TCP_MSG_1 ("DoSndDisconnect: OTSndOrderlyDisconnect returned an error");
01411             }
01412         }
01413     
01414     return (err);
01415     }/*DoSndDisconnect*/
01416 
01417 
01418 //
01419 //  EnterSndDisconnect
01420 //
01421 //  A thin wrapper around DoSndDisconnect.
01422 //  Called from fwsNetEventAbortStream to initiate an abortive disconnect.
01423 //
01424 static OSStatus EnterSndDisconnect (EndpointRecordRef epref) {
01425     
01426     OSStatus err;
01427     boolean doLeave = OTEnterNotifier (epref->ep);
01428     
01429     err = DoSndDisconnect (epref);
01430     
01431     if (doLeave)
01432         OTLeaveNotifier(epref->ep);
01433     
01434     return (err);
01435     }/*EnterSndDisconnect*/
01436 
01437 
01438 //
01439 //  ReadAndClose:
01440 //
01441 //  This routine attempts to read all available data from an endpoint.
01442 //  Check the endpoint state to see if there's any data left to be read.
01443 //  If so, read until we get an error -- most likely a kOTNoDataErr.
01444 //  
01445 //  Then check the endpoint state to see if we are in T_IDLE.  If so,
01446 //  the connection is fully broken down and we can unbind and requeue
01447 //  the endpoint for reuse.
01448 //
01449 //  Otherwise, the notifier will eventually get a T_ORDREL, T_DISCONNECT,
01450 //  or another T_DATA event and take care of the rest.
01451 //
01452 static void ReadAllAndClose (EndpointRecordRef epref) {
01453 
01454     OTResult epstate = OTGetEndpointState (epref->ep);
01455     
01456     switch (epstate) {
01457         
01458         case T_INREL:
01459             DoRcvOrderlyDisconnect (epref);
01460             return;
01461     
01462         case T_DATAXFER: {
01463             char buffer[kPacketSize];
01464             OTResult result;
01465             OTFlags junkFlags;
01466             
01467             do {
01468                 result = OTRcv (epref->ep, buffer, kPacketSize, &junkFlags);
01469                 } while (result >= 0);
01470         
01471             epstate = OTGetEndpointState (epref->ep);
01472             }
01473         }/*switch*/
01474 
01475     if (T_IDLE == epstate && 0 == OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)) {
01476         CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
01477         }
01478     }/*ReadAllAndClose*/
01479 
01480 
01481 static pascal void DNRNotifier (void *context, OTEventCode event, OTResult result, void *cookie) {
01482 
01483     #pragma unused (cookie)
01484     
01485     switch (event) {
01486 
01487         case T_DNRADDRTONAMECOMPLETE:
01488         case T_DNRSTRINGTOADDRCOMPLETE: {
01489             dnsquery *q = (dnsquery *) context;
01490             
01491             q->result = result;
01492             
01493             q->flags |= fcomplete;
01494             
01495             break;
01496             }
01497         }
01498 
01499     return;
01500     }/*dnsnotifier*/
01501 
01502 static pascal void ListenNotifier (void* context, OTEventCode code, OTResult result, void* cookie) {
01503 
01504     #pragma unused (cookie)
01505     
01506     ListenRecordRef listenref = (ListenRecordRef) context;
01507         
01508     switch (code) {
01509 
01510         /*
01511         T_DISCONNECT:
01512         
01513         Call DoListenRcvDisconnect to do all the work
01514         */
01515         case T_DISCONNECT: {
01516             DoListenRcvDisconnect (listenref);
01517             return;
01518             }
01519 
01520         /*
01521         T_DISCONNECTCOMPLETE:
01522         */
01523         case T_DISCONNECTCOMPLETE: {
01524             if (kOTNoError != result)
01525                 TCP_MSG_1 ("ListenNotifier: T_DISCONNECT_COMPLETE returned an error");
01526             return;
01527             }
01528         
01529         /*
01530         T_LISTEN:
01531         
01532         Call DoListenAccept() to do all the work.
01533         */
01534         case T_LISTEN: {
01535             DoListenAccept (listenref);
01536             break;
01537             }
01538 
01539         /*
01540         T_ACCEPTCOMPLETE:
01541 
01542         This event is received by the listener endpoint only.   
01543         The acceptor endpoint will get a T_PASSCON event instead.
01544         */
01545         case T_ACCEPTCOMPLETE:
01546             OTAssert ("ListenNotifier: T_ACCEPTCOMPLETE returned an error.", result == kOTNoError);
01547             return;
01548             
01549         /*
01550         default:
01551 
01552         There are events which we don't handle, but we don't expect to see
01553         any of them.   When running in debugging mode while developing a program,
01554         we exit with an informational alert.   Later, in the production version
01555         of the program, we ignore the event and try to keep running.
01556         */
01557         default: {
01558             TCP_MSG_1 ("ListenNotifier: unknown event");
01559             return;
01560             }
01561             
01562         }/*switch (event)*/
01563         
01564     }/*ListenNotifier*/
01565 
01566 static OSStatus SetIpReuseAddrOption (EndpointRecordRef epref) {
01567         
01568     TOptMgmt        optReq;
01569     TOption         opt;
01570 
01571     optReq.flags = T_NEGOTIATE;
01572     optReq.opt.len = kOTFourByteOptionSize;
01573     optReq.opt.buf = (unsigned char *) &opt;
01574     
01575     opt.len = sizeof(TOption);
01576     opt.level = INET_IP;
01577     opt.name = kIP_REUSEADDR;
01578     opt.status = 0;
01579     opt.value[0] = 1;
01580     
01581     return (OTOptionManagement (epref->ep, &optReq, nil));
01582     }/*SetIpReuseAddrOption*/
01583 
01584 
01585 static OSStatus SetTcpKeepAliveOption (EndpointRecordRef epref) {
01586 
01587     TOptMgmt            optReq;
01588     TKeepAliveOpt       opt;
01589 
01590     optReq.flags            = T_NEGOTIATE;
01591     optReq.opt.len          = sizeof (TKeepAliveOpt);
01592     optReq.opt.buf          = (unsigned char *) &opt;
01593     
01594     opt.len                 = sizeof (TKeepAliveOpt);
01595     opt.level               = INET_TCP;
01596     opt.name                = TCP_KEEPALIVE;
01597     opt.status              = 0;
01598     opt.tcpKeepAliveOn      = 1;
01599     opt.tcpKeepAliveTimer   = kTCPKeepAliveInMinutes;   
01600     
01601     return (OTOptionManagement (epref->ep, &optReq, nil));
01602     }/*SetTcpKeepAliveOption*/
01603 
01604 
01605 static OSStatus SetTcpConnAbortThresholdOption (EndpointRecordRef epref) {
01606 
01607     TOptMgmt        optReq;
01608     TOption         opt;
01609 
01610     optReq.flags = T_NEGOTIATE;
01611     optReq.opt.len = kOTFourByteOptionSize;
01612     optReq.opt.buf = (unsigned char *) &opt;
01613     
01614     opt.len = sizeof(TOption);
01615     opt.level = INET_TCP;
01616     opt.name = TCP_CONN_ABORT_THRESHOLD;
01617     opt.status = 0;
01618     opt.value[0] = kTCPWaitSecsForConnect * 1000; /*milliseconds*/
01619     
01620     return (OTOptionManagement (epref->ep, &optReq, nil));
01621     }/*SetTcpConnAbortThresholdOption*/
01622     
01623 
01624 static pascal void Notifier (void* context, OTEventCode code, OTResult result, void* cookie) {
01625 
01626     /*
01627     2002-10-30 AR: Fixed a possible connection leak in the T_PASSCON handler
01628     where we neglected to return the endpoint to the broken queue
01629     in case of an error.
01630     */
01631     
01632     EndpointRecordRef epref = (EndpointRecordRef) context;
01633     OSStatus err = noErr;
01634         
01635     switch (code) {
01636 
01637         /*
01638         T_OPENCOMPLETE:
01639         
01640         This event occurs when an OTAsyncOpenEndpoint() completes.   Note that this event,
01641         just like any other async call made from outside the notifier, can occur during
01642         the call to OTAsyncOpenEndpoint().  That is, in the main thread the program did
01643         the OTAsyncOpenEndpoint(), and the notifier is invoked before control is returned
01644         to the line of code following the call to OTAsyncOpenEndpoint().   This is one
01645         event we need to keep track of even if we are shutting down the program since there
01646         is no way to cancel outstanding OTAsyncOpenEndpoint() calls.
01647         */
01648         case T_OPENCOMPLETE: {
01649             
01650             /* Clear the OpenInProgress bit and check result of OTAsyncOpenEndpoint */
01651                 
01652             OTAtomicClearBit (&epref->stateflags, kOpenInProgressBit);
01653             
01654             if (kOTNoError == result)
01655                 epref->ep = (EndpointRef) cookie;
01656             else {
01657                 TCP_MSG_1 ("Notifier: T_OPENCOMPLETE returned an error");
01658                 ReturnEndpoint (epref, result, kConnectCompleteBit);
01659                 return;
01660                 }
01661 
01662             /* We should insert a test here to break out if we're in the process of shutting down the listener or the app */
01663             
01664             /* Set endpoint to blocking mode */
01665             
01666             err = OTSetBlocking (epref->ep);
01667             
01668             if (kOTNoError != err) {
01669                 TCP_MSG_1 ("Notifier: T_OPENCOMPLETE - OTSetBlocking returned an error");
01670                 ReturnEndpoint (epref, err, kConnectCompleteBit);
01671                 return;
01672                 }
01673                         
01674             /* Option Management - Turn on ip_reuseaddr so we don't have port conflicts in general. */
01675             
01676             if (kOTNoError != SetIpReuseAddrOption (epref)) {
01677                 TCP_MSG_2 ("Notifier: T_OPENCOMPLETE - OTOptionManagement returned an error");
01678                 ReturnEndpoint (epref, err, kConnectCompleteBit);
01679                 return;
01680                 }
01681             
01682             /* Code path resumes at T_OPTMGMTCOMPLETE */
01683             
01684             return;
01685             }
01686 
01687         /*
01688         T_OPTMGMTCOMPLETE:
01689         
01690         An OTOptionManagement() call has completed.  We set the ip_reuseaddr option
01691         for all endpoints right after they have been opened. We set the TCP_KEEPALIVE
01692         option for all endpoints every time we accept or intiate a new connection.
01693         We also set the TCP_CONN_ABORT_THRESHOLD option for all active endpoints
01694         whenever we we initiate a new connection.
01695         */
01696         case T_OPTMGMTCOMPLETE: {
01697 
01698             ListenRecordRef listenref = epref->listener;
01699             
01700             if (result != kOTNoError) {
01701                 TCP_MSG_2 ("Notifier: T_OPTMGMTCOMPLETE returned an error");
01702                 ReturnEndpoint (epref, result, kConnectCompleteBit);
01703                 return;
01704                 }
01705             
01706             if (nil != listenref) {
01707 
01708                 /*
01709                 This is the branch where we deal with passive endpoints that are used by
01710                 the listener to accept incoming connections. If we just opened the endpoint,
01711                 the T_OPENCOMPLETE handler just negotiated the ip_reuseaddr option.
01712                 In this case, the next thing to do is to add the endpoint to the list of idle endpoints.
01713                 If there is a connection pending, we accept it right away.
01714                 */
01715                 if (0 == OTAtomicSetBit (&epref->completionflags, kIPReuseAddrBit)) {
01716 
01717                     OTLIFOEnqueue (&listenref->idleEPs, &epref->link);
01718                     
01719                     listenref->stats.ctworking--;
01720 
01721                     listenref->stats.ctidle++;
01722                 
01723                     if (listenref->fllistenpending)
01724                         EnterListenAccept (listenref);
01725                     
01726                     return;
01727                     }
01728                 
01729                 /*
01730                 If we get here, the T_PASSCON handler just negotiated the TCP_KEEPALIVE option.
01731                 After setting the appropriate completion flag, we are ready to go to work.
01732                 */
01733                 if (0 == OTAtomicSetBit (&epref->completionflags, kTCPKeepAliveBit)) {
01734 
01735                     OTAtomicSetBit (&epref->stateflags, kDontDisposeBit);
01736 
01737                     OTLIFOEnqueue (&epref->listener->readyEPs, &epref->link);
01738                     
01739                     return;
01740                     }
01741                 
01742                 /*
01743                 We should never ever manage to get here, so post a debug message.
01744                 */
01745                 TCP_MSG_1 ("Notifier: T_OPTMGMTCOMPLETE got triggered unexpectedly");
01746                 return;
01747                 }
01748             
01749             else {              
01750 
01751                 /*
01752                 This is the branch where we deal with active endpoints. If we just opened the endpoint,
01753                 the last thing we did was to negotiate the ip_reuseaddr option. In this case,
01754                 the next thing to do is to bind the endpoint if it was opened by fwsOpenStream,
01755                 or to add it to the list of idle endpoints if it was re-opened by Recycle.
01756                 */
01757                 if (0 == OTAtomicSetBit (&epref->completionflags, kIPReuseAddrBit)) {
01758 
01759                     if (nil != epref->sendCall) {
01760 
01761                         /*
01762                         The endpoint was just opened by fwsOpenStream. The next thing to do is to bind it.
01763                         If the DoBind call succeeds, the code path will resume at T_BINDCOMPLETE.
01764                         */
01765                         err = DoBind (epref); 
01766                         
01767                         if (kOTNoError != err) {
01768                             TCP_MSG_2 ("Notifier: T_OPTMGMTCOMPLETE - DoBind returned an error");
01769                             ReturnEndpoint (epref, err, kConnectCompleteBit);
01770                             }
01771                         }
01772                     else {
01773                         
01774                         /*
01775                         The endpoint was just re-opened by Recycle. Now it's ready to go on the list of idle endpoints.
01776                         Eventually, it will be dequeued by fwsOpenStream in order to be bound again.
01777                         If that DoBind call succeeds, the code path will resume at T_BINDCOMPLETE.
01778                         */
01779                         OTLIFOEnqueue (&sIdleEPs, &epref->link);
01780                         
01781                         epstats.ctworking--;
01782                         
01783                         epstats.ctidle++;
01784                         }
01785                     
01786                     return;
01787                     }
01788                 
01789                 /*
01790                 If the TCP_KEEPALIVE flag hasn't been set yet, T_BINDCOMPLETE just negotiated the TCP_KEEPALIVE option.
01791                 In that case, the next thing to do is to also negotiate the TCP_CONN_ABORT_THRESHOLD option.
01792                 */
01793                 if (0 == OTAtomicSetBit (&epref->completionflags, kTCPKeepAliveBit)) {
01794                     
01795                     if (kOTNoError != SetTcpConnAbortThresholdOption (epref)) {
01796                         TCP_MSG_2 ("Notifier: T_OPTMGMTCOMPLETE - OTOptionManagement returned an error");
01797                         ReturnEndpoint (epref, err, kConnectCompleteBit);
01798                         }
01799                     
01800                     return;
01801                     }
01802                 
01803                 /*
01804                 We get here if both the TCP_KEEPALIVE and TCP_CONN_ABORT_THRESHOLD options have been negotiated.
01805                 Now we are ready to connect to the peer.
01806                 */
01807                 err = OTConnect (epref->ep, epref->sendCall, nil);
01808                 
01809                 if (err != kOTNoDataErr) {
01810                     /* anything other than kOTNoDataErr means that a connection has not been initiated */
01811                     TCP_MSG_1 ("Notifier: T_OPTMGMTCOMPLETE - OTConnect returned an error");
01812                     ReturnEndpoint (epref, err, kConnectCompleteBit);
01813                     return;
01814                     }
01815                 /*
01816                 If OTConnect returned the expected kOTNoDataErr, the code path will resume at T_CONNECT.
01817                 */
01818                 }
01819 
01820             return;
01821             }
01822 
01823         /*
01824         T_PASSCON:
01825 
01826         This event happens on the accepting endpoint, not the listening endpoint.
01827         At this point the connection is fully established and we can begin the
01828         process of downloading data.  Note that due to a problem in OT it is 
01829         possible for a T_DATA to beat a T_PASSCON to the notifier.  When this
01830         happens we note it in the T_DATA case and then start processing the 
01831         data here.
01832         */
01833         case T_PASSCON: {
01834                     
01835             if (kOTNoError != result) {
01836                 TCP_MSG_1 ("Notifier: T_PASSCON returned an error");
01837                 decrementconnectioncounter();
01838                 ReturnEndpoint (epref, result, kConnectCompleteBit); /* 2002-10-30 AR: don't leak endpoint */
01839                 return;
01840                 }   
01841             
01842             if (0 != OTAtomicSetBit (&epref->stateflags, kPassconBit)) {
01843 
01844                 /*
01845                 A T_DATA previously beat the T_PASSCON to our notifier.
01846                 Here we help OT out by having deferred data processing until now.
01847                 */
01848                 if (OTAtomicTestBit (&epref->stateflags, kWaitingForDisconnectBit)) {
01849                     ReadAllAndClose (epref);
01850                     return;
01851                     }               
01852                 }
01853             
01854             /*
01855             Before we can get to work, we need to negotiate the TCP_KEEPALIVE option.
01856             First, we set the ip_reuseaddr bit to make sure that
01857             the T_OPTMGMTCOMPLETE handler does the right thing.
01858             */
01859             OTAtomicSetBit (&epref->completionflags, kIPReuseAddrBit);
01860             
01861             if (kOTNoError != SetTcpKeepAliveOption (epref)) {
01862                 TCP_MSG_2 ("Notifier: T_PASSCON - OTOptionManagement returned an error");
01863                 ReturnEndpoint (epref, err, kConnectCompleteBit);
01864                 }
01865 
01866             /*
01867             If SetTcpKeepAliveOption succeeded, the code path will resume at T_OPTMGMTCOMPLETE.
01868             */
01869             return;
01870             }
01871 
01872         /*
01873         T_BINDCOMPLETE:
01874 
01875         This event is returned when an endpoint has been bound to a wildcard address.
01876         No errors are expected. We should only get here if the endpoint belongs
01877         to an active connection, initiated by fwsOpenStream rather than by a listener.
01878         We set the bound bit and the ip_reuseaddr bit so that the Notifier will do the right thing.
01879         Then we negotiate the TCP_KEEPALIVE option.
01880         */
01881         case T_BINDCOMPLETE: {
01882         
01883             if (kOTNoError != result) {
01884                 TCP_MSG_1 ("Notifier: T_BINDCOMPLETE returned an error");
01885                 ReturnEndpoint (epref, result, kConnectCompleteBit);
01886                 return;
01887                 }
01888             
01889             OTAtomicSetBit (&epref->stateflags, kBoundBit); /* so we know to unbind... */
01890             
01891             OTAtomicSetBit (&epref->completionflags, kIPReuseAddrBit); /* make sure we do the right thing in the notifier*/
01892             
01893             if (kOTNoError != SetTcpKeepAliveOption (epref)) {
01894                 TCP_MSG_2 ("Notifier: T_BINDCOMPLETE - OTOptionManagement returned an error");
01895                 ReturnEndpoint (epref, err, kConnectCompleteBit);
01896                 }
01897             
01898             /*
01899             If SetTcpKeepAliveOption succeeded, the code path will resume at T_OPTMGMTCOMPLETE.
01900             */
01901             return;
01902             }
01903         
01904         /*
01905         T_CONNECT:
01906 
01907         This event is returned when a connection is established to the server.
01908         The program must call OTRcvConnect() to get the connection information
01909         and clear the T_CONNECT event from the stream.  Since OTRcvConnect()
01910         returns immediately (rather than via a completion event to the notifier)
01911         we can use local stack structures for parameters.
01912         */
01913         case T_CONNECT: {
01914                     
01915             if (result != kOTNoError) {
01916                 TCP_MSG_1 ("Notifier: T_CONNECT returned an error");
01917                 ReturnEndpoint (epref, result, kConnectCompleteBit);
01918                 return;
01919                 }
01920             
01921             err = OTRcvConnect (epref->ep, nil);
01922 
01923             if (err != kOTNoError)
01924                 TCP_MSG_1 ("Notifier: T_CONNECT - OTRcvConnect returned an error");
01925             
01926             /* We're done, one way or another... */
01927             
01928             ReturnEndpoint (epref, err, kConnectCompleteBit);
01929             
01930             return;
01931             }
01932 
01933         /*
01934         T_DATA:
01935 
01936         The main rule for processing T_DATA's is to remember that once you have
01937         a T_DATA, you won't get another one until you have read to a kOTNoDataErr.
01938         The advanced rule is to remember that you could get another T_DATA
01939         during an OTRcv() which will eventually return kOTNoDataErr, presenting
01940         the application with a synchronization issue to be most careful about.
01941         */
01942         case T_DATA: {
01943             /*
01944             Here we work around a small OpenTransport bug.
01945             It turns out, since this program does almost everything from inside the notifier,
01946             that during a T_UNBINDCOMPLETE we can put an EPInfo back into the idle list.
01947             If that notification is interrupted by a T_LISTEN at the notifier, we could
01948             end up starting a new connection on the endpoint before OT unwinds the stack
01949             out of the code which delivered the T_UNBINDCOMPLETE.   OT has some specific
01950             code to protect against a T_DATA arriving before the T_PASSCON, but in this
01951             case it gets confused and the events arrive out of order.   If we try to
01952             do an OTRcv() at this point we will get a kOTStateChangeErr because the endpoint
01953             is still locked by the earlier OTAccept call until the T_PASSCON is delivered
01954             to us.   This is fairly benign and can be worked around easily.  What we do
01955             is note that the T_PASSCON hasn't arrived yet and defer the call to ReadData()
01956             until it does.
01957             */
01958             if (0 != OTAtomicSetBit (&epref->stateflags, kPassconBit)) {
01959                 /*
01960                 Because are are running completely inside notifiers,
01961                 it is possible for a T_DATA to beat a T_PASSCON to us.
01962                 We need to help OT out when this occurs and defer the
01963                 data read until the T_PASSCON arrives.
01964                 */              
01965                 if (OTAtomicTestBit (&epref->stateflags, kWaitingForDisconnectBit))
01966                     ReadAllAndClose (epref);                
01967                 }
01968             return;
01969             }
01970         
01971         /*
01972         T_GODATA:
01973         */
01974         case T_GODATA: {
01975             return;
01976             }
01977 
01978         /*
01979         T_ORDREL:
01980 
01981         This event occurs when an orderly release has been received on the stream.
01982         */
01983         case T_ORDREL: {
01984             
01985             DoRcvOrderlyDisconnect (epref);
01986                         
01987             return;
01988             }
01989         
01990         /*
01991         T_DISCONNECT:
01992         
01993         Call DoRcvDisconnect to do all the work
01994         */
01995         case T_DISCONNECT: {
01996             /*
01997             If the kWaitingForConnectBit is set, it means that the owning thread
01998             sits in a loop in fwsOpenStream, waiting for the connection request
01999             to complete. However, the peer didn't accept the connection, so we receive
02000             the disconnection request and return the reason for the disconnect
02001             to the owning thread in the epref->result field by calling DoRcvDisconnect.
02002             */
02003             
02004             if (OTAtomicTestBit (&epref->stateflags, kDontDisposeBit))
02005                 if (!OTAtomicTestBit (&epref->stateflags, kWaitingForConnectBit)
02006                     && !OTAtomicTestBit (&epref->stateflags, kWaitingForDisconnectBit)) {   
02007                         
02008                     /*
02009                     Deal with it in the worker thread.  We will get a kOTLookErr
02010                     when we try to read or write.  In that case we call OTLook,
02011                     and proceed to process the event.
02012                     */
02013                     return;
02014                     }
02015         
02016             DoRcvDisconnect (epref);
02017             
02018             if (OTAtomicTestBit (&epref->stateflags, kWaitingForConnectBit)) {
02019             
02020                 OTAtomicClearBit (&epref->stateflags, kWaitingForConnectBit);
02021                 
02022                 OTAtomicSetBit (&epref->completionflags, kConnectCompleteBit);
02023                 }
02024                 
02025             return;
02026             }
02027 
02028         /*
02029         T_DISCONNECTCOMPLETE:
02030         */
02031         case T_DISCONNECTCOMPLETE: {
02032             
02033             TCP_ASSERT_1 (!OTAtomicTestBit (&epref->stateflags, kDontDisposeBit));
02034                 
02035             if (result != kOTNoError)
02036                 TCP_MSG_1 ("Notifier: T_DISCONNECT_COMPLETE returned an error");
02037             
02038             CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
02039             
02040             return;
02041             }
02042 
02043         /*
02044         T_UNBINDCOMPLETE:
02045 
02046         This event occurs on completion of an OTUnbind().
02047         The endpoint is ready for reuse on a new inbound connection.
02048         Put it back into the queue of idle endpoints.
02049         Note that the OTLIFO structure has atomic queue and dequeue,
02050         which can be helpful for synchronization protection.  
02051         */
02052         case T_UNBINDCOMPLETE: {
02053             
02054             TCP_ASSERT_1 (!OTAtomicTestBit (&epref->stateflags, kDontDisposeBit));
02055         
02056             if (kOTNoError == result)
02057                 OTAtomicClearBit (&epref->stateflags, kBoundBit);
02058                 
02059             CheckUnbind (epref, result, kQueueIt);
02060             
02061             return;
02062             }
02063         
02064         /*
02065         T_GETPROTADDRCOMPLETE:
02066         
02067         GetProtAddress call initiated by fwsNetEventsGetPeerAddress is complete,
02068         so go ahead and set the completion flag.
02069         */
02070         case T_GETPROTADDRCOMPLETE: {
02071             OTAtomicSetBit (&epref->completionflags, kGetProtAddressBit);
02072             return;
02073             }
02074             
02075         /*
02076         default:
02077 
02078         There are events which we don't handle, but we don't expect to see
02079         any of them.   When running in debugging mode while developing a program,
02080         we exit with an informational alert.   Later, in the production version
02081         of the program, we ignore the event and try to keep running.
02082         */
02083         default: {
02084             //char str[256];
02085             //sprintf (str, "Notifier: unknown event (%08lx)", code);
02086             //TCP_MSG_1 (str);
02087             return;
02088             }
02089             
02090         }/*switch (code)*/
02091         
02092     }/*Notifier*/
02093 
02094 //
02095 //  EPOpen:
02096 //
02097 //  A front end to OTAsyncOpenEndpoint.
02098 //  A status bit is set so we know there is an open in progress.
02099 //  It is cleared when the notifier gets a T_OPENCOMPLETE where the context
02100 //  pointer is this EPInfo.  Until that happens, this EPInfo can't be cleaned
02101 //  up and released.
02102 //
02103 static OSStatus EPOpen (EndpointRecordRef epref, OTConfigurationRef cfg) {
02104 
02105     OSStatus err;
02106     
02107     //
02108     //  Clear all old state bits and set the open in progress bit.
02109     //  This doesn't need to be done atomicly because we are 
02110     //  single threaded on this endpoint at this point.
02111     //
02112     
02113     OTAtomicSetBit (&epref->stateflags, kOpenInProgressBit);
02114     
02115     #if TARGET_API_MAC_CARBON == 1
02116     err = OTAsyncOpenEndpointInContext (cfg, 0, nil, gNotifierUPP, epref, nil); //see OpenTransport.h line 1939
02117     
02118     #else   
02119     err = OTAsyncOpenEndpoint (cfg, 0, nil, &Notifier, epref);
02120     #endif
02121         
02122     if (kOTNoError != err)
02123         OTAtomicClearBit (&epref->stateflags, kOpenInProgressBit);
02124     
02125     return (err);
02126     }/*EPOpen*/
02127 
02128 
02129 //
02130 //  EPClose
02131 //
02132 //  This routine is a front end to OTCloseProvider.   Centralizing closing of
02133 //  endpoints makes debugging and instrumentation easier.   Also, since this
02134 //  program uses Ack Sends to avoid data copies when doing OTSnd(), some special
02135 //  care is required at close time.   
02136 //
02137 static boolean EPClose (EndpointRecordRef epref) {
02138 
02139     OSStatus err;
02140     
02141     /*
02142     If an endpoint is still being opened, we can't close it yet.
02143     There is no way to cancel an OTAsyncOpenEndpoint, so we just
02144     have to wait for the T_OPENCOMPLETE event at the notifier.
02145     */
02146     if (0 != OTAtomicTestBit (&epref->stateflags, kOpenInProgressBit))
02147         return (false);
02148     
02149     /*
02150     If the OTAsyncOpenEndpoint failed, the endpoint ref will be NULL,
02151     and we don't need to close it now.
02152     */
02153     if (nil == epref->ep)
02154         return true;
02155     
02156     err = OTCloseProvider (epref->ep);
02157     
02158     epref->ep = NULL;
02159         
02160     if (kOTNoError != noErr)
02161         TCP_MSG_1 ("EPClose: OTCloseProvider returned an error");
02162 
02163     return (true);
02164     }/*EPClose*/
02165 
02166 
02167 //
02168 //  Recycle:
02169 //
02170 //  This routine shouldn't be necessary, but it is helpful to work around both
02171 //  problems in OpenTransport and bugs in this program.   Basically, whenever an
02172 //  unexpected error occurs which shouldn't be fatal to the program, the EPInfo
02173 //  is queued on the BrokenEP queue.  When recycle is called, once per pass around
02174 //  the event loop, it will attempt to close the associated endpoint and open
02175 //  a new one to replace it using the same EPInfo structure.   This process of
02176 //  closing an errant endpoint and opening a replacement is probably the most
02177 //  reliable way to make sure that this program and OpenTransport can recover
02178 //  from unexpected happenings in a clean manner.
02179 //
02180 static void Recycle (ListenRecordRef listenref) {
02181 
02182     OTLink* nomad;
02183     OTLIFO* brokenlist;
02184     EndpointRecordRef epref;
02185     OTConfigurationRef cfg;
02186 
02187     if (nil != listenref) {
02188         brokenlist = &listenref->brokenEPs;
02189         cfg = listenref->masterconfig;
02190         }
02191     else {
02192         brokenlist = &sBrokenEPs;
02193         cfg = sMasterConfig;
02194         }
02195     
02196     nomad = OTLIFOStealList (brokenlist);
02197     
02198     while (nil != nomad) {
02199         
02200         epref = OTGetLinkObject (nomad, tyendpointrecord, link);
02201         
02202         nomad = nomad->fNext;
02203         
02204         if (!EPClose (epref)) {
02205 
02206             OTLIFOEnqueue (brokenlist, &epref->link);
02207                             
02208             continue;
02209             }
02210 
02211         OTAtomicClearBit (&epref->stateflags, kBrokenBit);
02212         
02213         InitEndpoint (epref, nil, listenref);
02214 
02215         if (kOTNoError != EPOpen (epref, OTCloneConfiguration (cfg))) {
02216         
02217             OTLIFOEnqueue (brokenlist, &epref->link);
02218         
02219             continue;
02220             }
02221         
02222         if (nil != listenref) {
02223             listenref->stats.ctbroken--;
02224             
02225             listenref->stats.ctworking++;
02226             }
02227         else {
02228             epstats.ctbroken--;
02229             
02230             epstats.ctworking++;
02231             }
02232         }/*while*/
02233     }/*Recycle*/
02234 
02235 
02236 static void ProcessWaitingEndpoints (ListenRecordRef listenref) {
02237 
02238     boolean doLeave;
02239     OTLink* nomad;
02240     EndpointRecordRef epref;
02241     OTLIFO* waitinglist = (listenref != nil) ? &listenref->waitingEPs : &sWaitingEPs;
02242     
02243     nomad = OTLIFOStealList (waitinglist);
02244     
02245     while (nil != nomad) {
02246         
02247         epref = OTGetLinkObject (nomad, tyendpointrecord, link);
02248         
02249         nomad = nomad->fNext;
02250         
02251         doLeave = OTEnterNotifier (epref->ep);
02252         
02253         /*bundle*/ {
02254         
02255             if (listenref != nil) { /*required to keep the stats accurate if CheckUnbind is called*/
02256                 listenref->stats.ctwaiting--;
02257                 listenref->stats.ctworking++;
02258                 }
02259             else {
02260                 epstats.ctwaiting--;
02261                 epstats.ctworking++;
02262                 }
02263             
02264             if (T_IDLE == OTGetEndpointState (epref->ep)) {
02265                 
02266                 OTAtomicClearBit (&epref->stateflags, kDontDisposeBit); /*pass on responsibility to the Notifier*/
02267                 
02268                 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
02269                 }
02270             else if (epref->timestamp + kTCPWaitSecsForOrderlyDisconnect < timenow())
02271                 DoSndDisconnect (epref);
02272             else {
02273             
02274                 if (listenref != nil) {
02275                     listenref->stats.ctworking--;
02276                     listenref->stats.ctwaiting++;
02277                     }
02278                 else {
02279                     epstats.ctworking--;
02280                     epstats.ctwaiting++;
02281                     }
02282 
02283                 OTLIFOEnqueue (waitinglist, &epref->link); /*try again later*/
02284                 }
02285             }
02286         
02287         if (doLeave)
02288             OTLeaveNotifier (epref->ep);
02289         }/*while*/
02290 
02291     }/*ProcessWaitingEndpoints*/
02292 
02293 
02294 static void gettcperrorstring (int errcode, bigstring bs) {
02295 
02296     int ixtcperr = errcode;
02297         
02298     if (IsEError (errcode)) {
02299     
02300         ixtcperr = OSStatus2E (errcode);
02301         
02302         copystring (stdcliberrorstrings [ixtcperr], bs); //handles nil source
02303         
02304         if (!isemptystring (bs)) {
02305             
02306             pushchar ('.', bs);
02307 
02308             return;
02309             }
02310         }
02311     
02312     if (IsXTIError (errcode)) {
02313     
02314         ixtcperr = OSStatus2XTI (errcode);
02315         
02316         copystring (xtierrorstrings [ixtcperr], bs); //handles nil source
02317         
02318         if (!isemptystring (bs)) {
02319             
02320             pushchar ('.', bs);
02321 
02322             return;
02323             }
02324         }
02325 
02326     getsystemerrorstring (errcode, bs); 
02327     } /*gettcperrorstring*/
02328 
02329 
02330 static void plainneterror (bigstring bs) {
02331 
02332     /*
02333     6.1b15 AR
02334     */
02335 
02336     bigstring errbs;
02337     
02338     copystring (bs, errbs);
02339 
02340     nullterminate (errbs);
02341     
02342     TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s", stringbaseaddress(errbs)));
02343     TCPERRORWRITEMSG ();
02344     
02345     langerrormessage (bs);
02346     } /*neterror*/
02347 
02348 
02349 static void closedunexpectedlyerror (char * cannot) {
02350 
02351     /*
02352     6.2b17 AR
02353     */
02354 
02355     bigstring bs;
02356     char prestring[256];
02357     
02358     wsprintf (prestring, "Can't %s because the TCP connection was closed unexpectedly.", cannot);
02359     copyctopstring (prestring, bs);
02360 
02361     plainneterror (bs);
02362     } /*neterror*/
02363 
02364 
02365 static void neterror (char * cannot, long errcode) {
02366 
02367     bigstring bs;
02368     bigstring errbs;
02369     char prestring[256];
02370 
02371     wsprintf (prestring, "Can't %s because TCP/IP error code %ld", cannot, (long)errcode);
02372     copyctopstring (prestring, errbs);
02373 
02374     gettcperrorstring (errcode, bs);
02375 
02376     if (!isemptystring (bs)) {
02377         
02378         pushstring (BIGSTRING ("\x03" " - "), errbs);
02379         
02380         pushstring (bs, errbs);
02381         }
02382     else {
02383         pushchar ('.', errbs);
02384         }
02385     
02386     nullterminate (errbs);
02387     
02388     TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s", stringbaseaddress(errbs)));
02389     TCPERRORWRITEMSG ();
02390     
02391     langerrormessage (errbs);
02392     } /*neterror*/
02393 
02394 #if 0
02395 
02396 static void dnserror (char *cannot, long errcode) {
02397     
02398     if (errcode == kOTBadNameErr) {  /* Host not found */
02399     
02400         bigstring bs;
02401         bigstring errbs;
02402         char prestring[256];
02403 
02404         wsprintf (prestring, "Can't %s because TCP/IP error code %ld", cannot, (long)errcode);
02405         copyctopstring (prestring, errbs);
02406 
02407         copystring (dnserrorstrings [1], bs); //handles nil source
02408                     
02409         pushstring (BIGSTRING ("\x03" " - "), errbs);
02410             
02411         pushstring (bs, errbs);
02412 
02413         pushchar ('.', errbs);
02414         
02415         nullterminate (errbs);
02416         
02417         TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s", stringbaseaddress(errbs)));
02418         TCPERRORWRITEMSG ();
02419         
02420         langerrormessage (errbs);
02421         
02422         return;
02423         }
02424 
02425     neterror (cannot, errcode);
02426     }
02427 
02428 #endif
02429 
02430 
02431 static void intneterror (long errcode) {
02432     bigstring bs;
02433 
02434     if (errcode == INTNETERROR_INVALIDSTREAM)
02435         copyctopstring ("Invalid stream", bs);
02436     else
02437         copyctopstring ("Unknown stream error", bs);
02438 
02439     langerrormessage (bs);
02440     } /*intneterror*/
02441 
02442 
02443 static boolean fwsbackgroundtask (void) {
02444 
02445     boolean fl = true;
02446 
02447     if (inmainthread ()) {
02448         EventRecord     ev;
02449         short mask = osMask|activMask|mDownMask|keyDownMask; //|highLevelEventMask|updateMask
02450         long sleepTime = 6; // 1/10 of a second by default
02451         
02452         if (WaitNextEvent (mask, &ev, sleepTime, nil)) /*migh return false to indicate a null event, but that's not an error*/
02453             fl = shellprocessevent (&ev);
02454         }
02455     else
02456         fl = langbackgroundtask (true);
02457     
02458     return (fl);
02459     }/*fwsbackgroundtask*/
02460 
02461 
02462 static boolean fwsNetEventLaunch (void *data) {
02463 #pragma unused (data)
02464 
02465     /*
02466     Initialize the NetEvents system 
02467 
02468     5.0.2b5 dmb: added hostData parameter and GUSI support to handle threading
02469     */
02470 
02471     if (!frontierWinSockLoaded) {
02472         
02473         //Code change by Timothy Paustian Monday, June 26, 2000 3:55:47 PM
02474         //OpenTransport takes a context for all of its calls. Applications
02475         //do not need this, so pass nil
02476         OSStatus err = noErr;
02477         
02478         #if TARGET_API_MAC_CARBON ==1
02479             err = InitOpenTransportInContext(kInitOTForApplicationMask, nil);
02480         #else
02481             err = InitOpenTransport ();
02482         #endif
02483     
02484         if (err != kOTNoError) {
02485             neterror ("initialize Open Transport", err);
02486             return (false);
02487             }
02488 
02489         err = Gestalt (sOTVersionSelector, (long*) &sOTVersion);
02490         
02491         if (err || (sOTVersion < kOTVersion111)) {
02492             plainneterror (BIGSTRING ("\x23" "Please install Open Transport 1.1.1 or later."));
02493             return (false);
02494             }
02495         
02496         clearbytes (&epstats, sizeof (epstats));
02497         
02498         sListenList.fHead = nil;
02499         sEndpointList.fHead = nil;
02500 
02501         sIdleEPs.fHead = nil;
02502         sBrokenEPs.fHead = nil;
02503         sWaitingEPs.fHead = nil;
02504         
02505         sMasterConfig = OTCreateConfiguration ("tcp");
02506         
02507         #if TARGET_API_MAC_CARBON == 1
02508             gThreadEntryCallback = NewThreadEntryUPP (fwsacceptingthreadmain);
02509             
02510             if(gThreadEntryCallback == nil) {
02511                 memoryerror ();
02512                 return (false);
02513                 }
02514                 
02515             gListenNotifierUPP = NewOTNotifyUPP(ListenNotifier);
02516             
02517             if(gListenNotifierUPP == nil) {
02518                 memoryerror ();
02519                 return (false);
02520                 }
02521             
02522             gListSearchUPP = NewOTListSearchUPP(listenlinkvisit);
02523             
02524             if(gListSearchUPP == nil) {
02525                 memoryerror ();
02526                 return (false);
02527                 }
02528             
02529             gNotifierUPP = NewOTNotifyUPP(Notifier);
02530             
02531             if(gNotifierUPP == nil) {
02532                 memoryerror ();
02533                 return (false);
02534                 }
02535             
02536             gDNRNotifierUPP = NewOTNotifyUPP (DNRNotifier);
02537             
02538             if (gDNRNotifierUPP == nil) {
02539                 memoryerror ();
02540                 return (false);
02541                 }
02542                 
02543             gEndListSearchUPP = NewOTListSearchUPP(endpointlinkvisit);
02544             
02545             if(gEndListSearchUPP == nil) {
02546                 memoryerror ();
02547                 return (false);
02548                 }
02549                 
02550         #endif
02551         }
02552         
02553     frontierWinSockLoaded = true;
02554     
02555     ++frontierWinSockCount;
02556 
02557     return (true);
02558     } /*fwsNetEventLaunch*/
02559 
02560 
02561 boolean fwsNetEventQuit (void) {
02562 
02563     frontierWinSockCount = 0;
02564 
02565     TCPTRACKERCLOSE();
02566 
02567     if (frontierWinSockLoaded) {
02568         frontierWinSockLoaded = false;
02569 
02570         //Code change by Timothy Paustian Sunday, May 7, 2000 9:29:38 PM
02571         //Changed to Opaque call for Carbon
02572         #if TARGET_API_MAC_CARBON == 1
02573 
02574             //get rid of our UPPs
02575             DisposeOTNotifyUPP(gNotifierUPP);
02576             gNotifierUPP = nil;
02577             DisposeOTNotifyUPP (gDNRNotifierUPP);
02578             DisposeOTListSearchUPP(gEndListSearchUPP);
02579             gEndListSearchUPP = nil;
02580             DisposeOTListSearchUPP(gListSearchUPP);
02581             gListSearchUPP = nil;
02582             DisposeOTNotifyUPP(gListenNotifierUPP);
02583             gListenNotifierUPP = nil;
02584             DisposeThreadEntryUPP(gThreadEntryCallback);
02585             gThreadEntryCallback = nil;
02586 
02587             //This has to be switched to NULL when we link against the carbon lib.
02588             CloseOpenTransportInContext(nil);
02589         #else
02590             CloseOpenTransport ();
02591         #endif
02592 
02593         return (true);
02594         }
02595 
02596     return (false);
02597     } /*fwsNetEventShutDown*/
02598 
02599 
02600 boolean fwsNetEventAddressDecode (unsigned long addr, bigstring IPaddr) {
02601     
02602     /* Convert an address (4 byte) into a dotted IP address */
02603 
02604     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02605         return (false);
02606     
02607     setstringlength (IPaddr, 0);
02608     
02609     OTInetHostToString (addr, (char *)(stringbaseaddress (IPaddr)));
02610     
02611     setstringlength (IPaddr, strlen (stringbaseaddress ((char *)IPaddr)));
02612 
02613     return (true);
02614     } /*fwsNetEventAddressDecode*/
02615 
02616 
02617 boolean fwsNetEventAddressEncode (bigstring IPaddr, unsigned long  * addr) {
02618     
02619     /* Convert a dotted IP address into an address (4 byte) */
02620 
02621     InetHost host;
02622     OSStatus err;
02623 
02624     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02625         return (false);
02626     
02627     nullterminate (IPaddr);
02628     
02629     err = OTInetStringToHost (stringbaseaddress ((char *)IPaddr), &host);
02630     
02631     if (err != kOTNoError) {
02632     
02633         langparamerror (cantencodeaddress, IPaddr);
02634     
02635         return (false);
02636         }
02637 
02638     *addr = host;
02639     
02640     return (true);
02641     } /*fwsNetEventAddressEncode*/
02642     
02643 
02644 boolean fwsNetEventAddressToName (unsigned long addr, bigstring domainName) {
02645 
02646     /*
02647     Convert an address (4 byte) into a domain name
02648     */
02649 
02650     dnsquery query;
02651     InetSvcRef inetservice;
02652     OSStatus err;
02653 
02654     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02655         return (false);
02656     
02657     TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventAddressToName at line %d.  Address: %ld.", __LINE__, addr));
02658     TCPWRITEMSG();
02659 
02660     /*open dns service provider*/
02661 
02662     #if TARGET_API_MAC_CARBON == 1
02663         inetservice = OTOpenInternetServicesInContext (kDefaultInternetServicesPath, 0L, &err, nil);
02664     #else
02665         inetservice = OTOpenInternetServices (kDefaultInternetServicesPath, 0L, &err);
02666     #endif
02667     
02668     if (err != kOTNoError) {
02669         neterror("convert address", err);
02670         return (false);
02671         }
02672     
02673     /*install the notifier*/
02674     
02675     OTMemzero (&query, sizeof (query));
02676     
02677     #if TARGET_API_MAC_CARBON == 1
02678         err = OTInstallNotifier (inetservice, gDNRNotifierUPP, &query);
02679     #else
02680         err = OTInstallNotifier (inetservice, &DNRNotifier, &query);
02681     #endif
02682     
02683     if (err != kOTNoError) 
02684         goto exit;
02685 
02686     /*switch to async mode*/
02687         
02688     err = OTSetAsynchronous (inetservice);
02689 
02690     if (err != kOTNoError) 
02691         goto exit2;
02692     
02693     /*fire off query*/
02694     
02695     err = OTInetAddressToName (inetservice, (InetHost) addr, stringbaseaddress ((char *)domainName));
02696 
02697     if (err != kOTNoError) 
02698         goto exit2;
02699 
02700     /*spin until query completes*/
02701     
02702     while (0 == (query.flags & fcomplete))
02703         YieldToAnyThread ();
02704 
02705     /*clean up*/
02706     
02707     #if TARGET_API_MAC_CARBON == 1
02708         OTRemoveNotifier (inetservice);
02709     #endif
02710 
02711     OTCloseProvider (inetservice);
02712     
02713     /*retrieve query result and return*/
02714     
02715     if (query.result != kOTNoError) {
02716         neterror ("convert address", query.result);
02717         return (false);
02718         }
02719     
02720     setstringlength (domainName, strlen (stringbaseaddress ((char *)domainName)));
02721     
02722     poptrailingchars (domainName, '.');
02723 
02724     TCPprintf (wsprintf(TCPmsg, "Leaving fwsNetEventAddressToName at line %d.  Domain name: %s.", __LINE__, stringbaseaddress (domainName)));
02725     TCPWRITEMSG();
02726 
02727     return (true);
02728     
02729     /*error handling*/
02730     
02731 exit2:
02732 
02733     #if TARGET_API_MAC_CARBON == 1
02734         OTRemoveNotifier (inetservice);
02735     #endif
02736 
02737 exit:
02738     
02739     OTCloseProvider (inetservice);
02740 
02741     neterror ("convert name", err);
02742     
02743     return (false);
02744     } /*fwsNetEventAddressToName*/
02745 
02746 
02747 boolean fwsNetEventNameToAddress (bigstring domainName, unsigned long * addr) {
02748     
02749     /*
02750     Convert a domain name into an address (4 byte)
02751     
02752     7.0b44 PBS: OS X -- make the domain name all lower to prevent an error.
02753     */
02754 
02755     char sysstring[256];
02756     dnsquery query;
02757     InetHostInfo hostinfo;
02758     InetSvcRef inetservice;
02759     OSStatus err;
02760     
02761     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02762         return (false);
02763 
02764     TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventNameToAddress at line %d.  Domain name: %s.", __LINE__, stringbaseaddress (domainName)));
02765     TCPWRITEMSG();
02766     
02767     #if TARGET_API_MAC_CARBON == 1
02768     
02769         alllower (domainName); /*7.0b44 PBS: OS X may return an error otherwise.*/
02770         
02771     #endif
02772        
02773     copyptocstring (domainName, sysstring);
02774     
02775     /*open dns service provider*/
02776 
02777     #if TARGET_API_MAC_CARBON == 1
02778         inetservice = OTOpenInternetServicesInContext (kDefaultInternetServicesPath, 0L, &err, nil);
02779     #else
02780         inetservice = OTOpenInternetServices (kDefaultInternetServicesPath, 0L, &err);
02781     #endif
02782     
02783     if (err != kOTNoError) {
02784         neterror("convert name", err);
02785         return (false);
02786         }
02787     
02788     /*install the notifier*/
02789     
02790     OTMemzero (&query, sizeof (query));
02791     
02792     #if TARGET_API_MAC_CARBON == 1
02793         err = OTInstallNotifier (inetservice, gDNRNotifierUPP, &query);
02794     #else
02795         err = OTInstallNotifier (inetservice, &DNRNotifier, &query);
02796     #endif
02797     
02798     if (err != kOTNoError) 
02799         goto exit;
02800 
02801     /*switch to async mode*/
02802         
02803     err = OTSetAsynchronous (inetservice);
02804         
02805     if (err != kOTNoError) 
02806         goto exit;
02807 
02808     /*fire off query*/
02809     
02810     err = OTInetStringToAddress (inetservice, sysstring, &hostinfo);
02811     
02812     if (err != kOTNoError) 
02813         goto exit;
02814 
02815     /*spin until query completes*/
02816     
02817     while (0 == (query.flags & fcomplete))
02818         YieldToAnyThread ();
02819 
02820     /*clean up*/
02821     
02822     OTCloseProvider (inetservice);
02823     
02824     /*retrieve query result and return*/
02825     
02826     if (query.result != kOTNoError) {
02827         neterror ("convert name", query.result);
02828         return (false);
02829         }
02830             
02831     *addr = hostinfo.addrs[0];
02832 
02833     TCPprintf (wsprintf(TCPmsg, "Leaving fwsNetEventNameToAddress at line %d.  Address: %08lx.", __LINE__, *addr));
02834     TCPWRITEMSG();
02835 
02836     return (true);
02837     
02838     /*error handling*/
02839 
02840 exit:
02841     
02842     OTCloseProvider (inetservice);
02843 
02844     neterror ("convert name", err);
02845     
02846     return (false);
02847     } /*fwsNetEventNameToAddress*/
02848 
02849 
02850 boolean fwsNetEventMyAddress (unsigned long * addr) {
02851     
02852     /* Get the hosts address */
02853 
02854     OSStatus err;
02855     OSStatus junk;
02856     EndpointRef dummyEP;
02857     InetInterfaceInfo info;
02858     Boolean fl = false;
02859     TEndpointInfo epInfo;
02860 
02861     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02862         return (false);
02863 
02864     //Code change by Timothy Paustian Monday, June 26, 2000 4:04:28 PM
02865     //
02866     #if TARGET_API_MAC_CARBON == 1
02867         dummyEP = OTOpenEndpointInContext (OTCreateConfiguration ("tcp"), 0, &epInfo, &err, nil);
02868     #else   
02869         dummyEP = OTOpenEndpoint (OTCreateConfiguration ("tcp"), 0, &epInfo, &err);
02870     #endif
02871     
02872     if (err != kOTNoError) {
02873         neterror("get local address", err);
02874         return (false);
02875         }
02876     
02877     err = OTInetGetInterfaceInfo (&info, 0);
02878     
02879     if (err == kOTNoError) {
02880         
02881         *addr = info.fAddress;
02882         
02883         fl = true;
02884         }
02885     else
02886         neterror("get local address", err);
02887 
02888     if (dummyEP != nil) {
02889         junk = OTCloseProvider(dummyEP);
02890         OTAssert("fwsNetEventMyAddress: Failed closing dummy endpoint", junk == kOTNoError);
02891         }
02892     
02893     return (fl);
02894     } /*fwsNetEventMyAddress*/
02895 
02896 
02897 static boolean fwsgetcallbackcodetree (bigstring bs, Handle *htree) {
02898         
02899     Handle htext;
02900     boolean fl;
02901     unsigned long savelines;
02902     unsigned short savechars;
02903     hdltreenode hmodule = nil;
02904     
02905     if (!newtexthandle (bs, &htext))
02906         return (false);
02907     
02908     savelines = ctscanlines;
02909     
02910     savechars = ctscanchars;
02911     
02912     fl = langcompiletext (htext, false, &hmodule); /*always disposes htext*/
02913         
02914     ctscanlines = savelines;
02915     
02916     ctscanchars = savechars;
02917     
02918     if (!fl)
02919         return (false); 
02920     
02921     fl = langpacktree ((**hmodule).param1, htree); /*make a copy of the sub-tree*/
02922 
02923     langdisposetree (hmodule);
02924     
02925     return (fl);
02926     } /*fwsgetcallbackcodetree*/
02927 
02928 
02929 static boolean fwsnewprocess (hdltreenode hcode, bigstring bsname, hdlprocessrecord *hprocess) {
02930         
02931     register hdlprocessrecord hp;
02932     hdlerrorstack herrorstack;
02933     hdltablestack htablestack;
02934     tyerrorrecord item;
02935     
02936     if (!newclearhandle (sizeof (typrocessrecord), (Handle *) hprocess))
02937         return (false);
02938     
02939     hp = *hprocess; /*copy into register*/
02940     
02941     if (!newclearhandle (sizeof (tyerrorstack), (Handle *) &herrorstack)) {
02942         
02943         disposehandle ((Handle) hp);
02944         
02945         return (false);
02946         }
02947     
02948     if (!newclearhandle (sizeof (tytablestack), (Handle *) &htablestack)) {
02949         
02950         disposehandle ((Handle) hp);
02951         
02952         disposehandle ((Handle) herrorstack);
02953         
02954         return (false);
02955         }
02956     
02957     (**hp).hcode = hcode;
02958     
02959     (**hp).floneshot = true;
02960     
02961     (**hp).errormessagecallback = &langerrordialog;
02962 
02963     (**hp).debugerrormessagecallback = (langerrormessagecallback) &truenoop;
02964     
02965     (**hp).htablestack = htablestack;
02966     
02967     (**hp).herrorstack = herrorstack;
02968     
02969     (**hp).processstartedroutine = (langvoidcallback) &truenoop;
02970     
02971     (**hp).processkilledroutine = (langvoidcallback) &truenoop;
02972         
02973     item.errorcallback = nil;
02974     
02975     item.errorline = 0;
02976     
02977     item.errorchar = 0; 
02978     
02979     item.errorrefcon = 0;
02980 
02981 #ifdef flnewfeatures
02982     item.profilebase = 0;       
02983 #endif
02984     
02985     (**herrorstack).stack [(**herrorstack).toperror++] = item;
02986 
02987     copystring (bsname, (**hp).bsname);
02988 
02989     return (true);
02990     } /*newprocess*/
02991     
02992 
02993 static boolean fwsruncallback (EndpointRecordRef epref) {
02994 
02995     hdltreenode hcallbackaddress;
02996     hdltreenode hfunctioncall;
02997     hdltreenode hcode;
02998     hdltreenode hparam1;
02999     hdltreenode hparam2;
03000     tyvaluerecord val;
03001     hdlprocessrecord hprocess;
03002     Handle h;
03003     
03004     ListenRecordRef listenref = epref->listener;
03005     long refcon = listenref->refcon;
03006     Handle hcallbacktree = listenref->hcallbacktree;
03007     bigstring bsname;
03008     
03009     copystring (listenref->callback, bsname);
03010     
03011     //build code tree
03012     
03013     if (!copyhandle (hcallbacktree, &h))
03014         return (false);
03015         
03016     if (!langunpacktree (h, &hcallbackaddress))
03017         return (false);
03018     
03019     setlongvalue ((long) epref, &val);
03020     
03021     if (!newconstnode (val, &hparam1)) {
03022         langdisposetree (hcallbackaddress);
03023         return (false);
03024         }
03025     
03026     setlongvalue (refcon, &val);
03027     
03028     if (!newconstnode (val, &hparam2)) {
03029         langdisposetree (hcallbackaddress);
03030         langdisposetree (hparam1);
03031         return (false);
03032         }
03033     
03034     pushlastlink (hparam2, hparam1);
03035     
03036     if (!pushbinaryoperation (functionop, hcallbackaddress, hparam1, &hfunctioncall))
03037         return (false);
03038         
03039     if (!pushbinaryoperation (moduleop, hfunctioncall, nil, &hcode))
03040         return (false);
03041 
03042     //create new process
03043     
03044     if (!fwsnewprocess (hcode, bsname, &hprocess)) {
03045         langdisposetree (hcode);
03046         return (false);
03047         }
03048 
03049     //add new process
03050 
03051     return (addprocess (hprocess));
03052     }/*fwsruncallback*/
03053 
03054 
03055 static long fwsprocesspendingconnections (ListenRecordRef listenref) {
03056 
03057     OTLink* nomad = OTLIFOStealList (&listenref->readyEPs);
03058     OTLink* next;
03059     EndpointRecordRef epref;
03060     long ct = 0;
03061     boolean fl;
03062     
03063     while (nil != nomad) {
03064         
03065         next = nomad->fNext;
03066 
03067         epref = OTGetLinkObject (nomad, tyendpointrecord, link);
03068                     
03069         OTAddFirst (&sEndpointList, &epref->validationlink);
03070         
03071         epref->typeID = SOCKTYPE_OPEN;
03072 
03073         TCPprintf (wsprintf (TCPmsg, "In fwsacceptpendingconnections at line %d.  Accepted new connection #%08ld on listener %08lx: %s (%08lx, %ld).",
03074                                         __LINE__, ct, (long) listenref, stringbaseaddress (listenref->callback), (long) epref, listenref->refcon));
03075         TCPWRITEMSG();
03076 
03077         fl = fwsruncallback (epref);
03078     
03079         TCP_ASSERT_1 (fl);  
03080 
03081         nomad = next;
03082         
03083         ct++;
03084         }/*while*/
03085         
03086     return (ct);
03087     }/*fwsprocesspendingconnections*/
03088 
03089 
03090 static void fwscleanuplistener (ListenRecordRef listenref) {
03091 
03092     EndpointRecordRef epref;
03093     OTLink* nomad;
03094     OTLink* next;
03095     long ctepsclosed = 0;
03096     
03097     /* Process pending connections for one last time */
03098     
03099     fwsprocesspendingconnections (listenref); /* listenref->readyEPs is now empty and remains empty */
03100     
03101     /* Now enter a loop in which we close idle and broken eps until we've closed all dependent acceptors */
03102 
03103     while (ctepsclosed < listenref->maxdepth) {
03104     
03105         YieldToAnyThread ();
03106 
03107         nomad = OTLIFOStealList (&listenref->idleEPs);
03108         
03109         while (nomad != nil) {
03110                     
03111             next = nomad->fNext;
03112             
03113             epref = OTGetLinkObject (nomad, tyendpointrecord, link);
03114             
03115             nomad = next;
03116             
03117             if (EPClose (epref)) {
03118             
03119                 ++ctepsclosed;
03120 
03121                 listenref->stats.ctidle--;
03122                 }
03123             else {
03124                 OTLIFOEnqueue (&listenref->brokenEPs, &epref->link);
03125 
03126                 listenref->stats.ctidle--;
03127                 
03128                 listenref->stats.ctbroken++;
03129                 }
03130             }/*while*/
03131             
03132         YieldToAnyThread ();
03133 
03134         nomad = OTLIFOStealList (&listenref->brokenEPs);
03135         
03136         while (nomad != nil) {
03137                     
03138             next = nomad->fNext;
03139             
03140             epref = OTGetLinkObject (nomad, tyendpointrecord, link);
03141             
03142             nomad = next;
03143             
03144             if (EPClose (epref)) {
03145             
03146                 ++ctepsclosed;
03147                 
03148                 listenref->stats.ctbroken--;
03149                 }
03150             else
03151                 OTLIFOEnqueue (&listenref->brokenEPs, &epref->link);
03152             }/*while*/
03153             
03154         }/*while*/
03155     
03156     assert (listenref->stats.ctbroken == 0);
03157     
03158     assert (listenref->stats.ctidle == 0);
03159     
03160     assert (listenref->stats.ctworking == 0);
03161     
03162     /* Finally, dispose all allocated memory structures */
03163     
03164     OTDestroyConfiguration (listenref->masterconfig);
03165 
03166     disposehandle (listenref->hcallbacktree);
03167     
03168     DisposePtr ((Ptr) listenref->acceptors);
03169     
03170     DisposePtr ((Ptr) listenref);
03171     
03172     return;
03173     }/*fwscleanuplistener*/
03174 
03175 
03176 static void *fwsacceptingthreadmain (void *param) {
03177 
03178     /*
03179     We sit in a loop waiting for connections that are ready to be picked up and sent to the daemon.
03180     We are also responsible for shutting down the listener and all dependent endpoints.
03181     */
03182 
03183     ListenRecordRef listenref = (ListenRecordRef) param;
03184     OSStatus err;
03185     long ct = 0;
03186 
03187     TCPTRACKERIN ("fwsacceptingthreadmain", __LINE__, nil, listenref);
03188     
03189     while (SOCKTYPE_LISTENSTOPPED != listenref->typeID) {
03190         
03191         ct += fwsprocesspendingconnections (listenref);
03192                 
03193         ProcessWaitingEndpoints (listenref);
03194         
03195         Recycle (listenref);
03196 
03197         if (listenref->fllistenpending)
03198             EnterListenAccept (listenref);
03199         
03200         err = YieldToAnyThread ();
03201         
03202         TCP_ASSERT_1 (err == kOTNoError);   
03203         }/*while*/
03204     
03205     TCPprintf (wsprintf (TCPmsg, "In fwsacceptingthreadmain at line %d, broke out of loop after accepting %ld connections on listener %08lx. Now starting clean-up.",
03206                             __LINE__, ct, (long) listenref));
03207     TCPWRITEMSG();
03208 
03209     fwscleanuplistener (listenref); 
03210 
03211     TCPprintf (wsprintf (TCPmsg, "Exiting fwsacceptingthreadmain at line %d.", __LINE__));
03212     TCPWRITEMSG();
03213 
03214     return (nil);
03215     }/*fwsacceptingthreadmain*/
03216 
03217 
03218 static boolean fwslaunchacceptingthread (ListenRecordRef listenref) {
03219 
03220     OSStatus err;
03221 
03222     #if TARGET_API_MAC_CARBON == 1
03223         err = NewThread (kCooperativeThread, gThreadEntryCallback, (void *)listenref, 0, kUsePremadeThread + kCreateIfNeeded + kFPUNotNeeded, nil, (ThreadID *)(&listenref->idthread));
03224     #else
03225         err = NewThread (kCooperativeThread, fwsacceptingthreadmain, (void *)listenref, 0, kUsePremadeThread + kCreateIfNeeded + kFPUNotNeeded, nil, (ThreadID *)(&listenref->idthread));
03226     #endif
03227 
03228     if (kOTNoError != err) {
03229         oserror (err);
03230         return (false); 
03231         }
03232 
03233     return (true);
03234     }/*fwslaunchacceptingthread*/
03235 
03236 
03237 boolean fwsNetEventListenStream (unsigned long port, long depth, bigstring pCallback, unsigned long refcon, unsigned long * stream, unsigned long ipaddr, long hdatabase) {
03238 
03239     /* Set up a listner on a port */
03240 
03241     Handle hcallbacktree = nil;
03242     OSStatus err;
03243     TBind bindReq;
03244     InetAddress ipAddress;
03245     ListenRecordRef listenref = nil;
03246     EndpointRecordRef epref = nil;
03247     TOptMgmt optReq;
03248     TOption opt;
03249     long i;
03250     
03251     nullterminate (pCallback);
03252     TCPprintf(wsprintf(TCPmsg, "Entering fwsNetEventListenStream at line %d. Port = %ld, Depth = %ld, Refcon = %ld, Callback = %s.", __LINE__, port, depth, refcon, stringbaseaddress(pCallback)));
03253     TCPWRITEMSG ();
03254 
03255     /* Initialize Open Transport and static data structures */
03256     
03257     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03258         return (false);
03259     
03260     /* Compile and pack a code tree for the address of the daemon script */
03261 
03262     if (!fwsgetcallbackcodetree (pCallback, &hcallbacktree))
03263         return (false);
03264     
03265     /* Allocate and clear memory for the listener */
03266     
03267     listenref = (ListenRecordRef) NewPtr (sizeof (tylistenrecord));
03268 
03269     if (listenref == nil) {
03270         memoryerror ();
03271         goto exit;
03272         }
03273     
03274     OTMemzero (listenref, sizeof (tylistenrecord));
03275     
03276     /* Initialize further status fields */
03277     copystring (pCallback, listenref->callback);
03278 
03279     listenref->maxdepth = depth;
03280 
03281     listenref->refcon = refcon;
03282     
03283     listenref->hcallbacktree = hcallbacktree;
03284 
03285     listenref->hdatabase = (hdldatabaserecord) hdatabase;
03286     
03287     /* Open synchronous listener and set to blocking mode */
03288 
03289     #if TARGET_API_MAC_CARBON == 1
03290         listenref->ep = OTOpenEndpointInContext (OTCreateConfiguration ("tilisten,tcp"), nil, nil, &err, nil);
03291     #else
03292         listenref->ep = OTOpenEndpoint (OTCreateConfiguration ("tilisten,tcp"), nil, nil, &err);
03293     #endif
03294     
03295     if (kOTInvalidEndpointRef == listenref->ep || kOTNoError != err) {
03296         neterror ("create listen stream", err);
03297         goto exit;
03298         }
03299     
03300     err = OTSetBlocking (listenref->ep);
03301     
03302     if (kOTNoError != err) {
03303         OSStatus status;
03304         status = OTCloseProvider (listenref->ep);   
03305         OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError);
03306         neterror ("set listen stream to blocking mode", err);
03307         goto exit;
03308         }
03309     
03310     /* Option Management - Turn on ip_reuseaddr so we don't have port conflicts in general. */
03311 
03312     optReq.flags = T_NEGOTIATE;
03313     optReq.opt.len = kOTFourByteOptionSize;
03314     optReq.opt.buf = (unsigned char *) &opt;
03315     
03316     opt.len = sizeof (TOption);
03317     opt.level = INET_IP;
03318     opt.name = kIP_REUSEADDR;
03319     opt.status = 0;
03320     opt.value[0] = 1;
03321 
03322     err = OTOptionManagement (listenref->ep, &optReq, nil);
03323 
03324     if (kOTNoError != err) {
03325         OSStatus status;
03326         status = OTCloseProvider (listenref->ep);   
03327         OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError);
03328         neterror ("set IP_REUSEADDR option on listen stream", err);
03329         goto exit;
03330         }
03331 
03332     /* Bind listener to specified address or default address if ipaddr is nil */
03333 
03334     OTInitInetAddress (&ipAddress, port, ipaddr);
03335     
03336     bindReq.addr.buf = (UInt8 *) &ipAddress;
03337     
03338     bindReq.addr.len = sizeof (ipAddress);
03339     
03340     bindReq.qlen = depth;
03341     
03342     err = OTBind (listenref->ep, &bindReq, nil);
03343 
03344     if (kOTNoError != err) {
03345         OSStatus status;
03346         status = OTCloseProvider (listenref->ep);   
03347         OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError);
03348         neterror ("bind listen stream", err);
03349         goto exit;
03350         }   
03351 
03352     /* Install a notifier for the listener and switch to async mode */
03353     #if TARGET_API_MAC_CARBON == 1
03354         err = OTInstallNotifier (listenref->ep, gListenNotifierUPP, (void *) listenref);
03355     #else
03356         err = OTInstallNotifier (listenref->ep, &ListenNotifier, (void *) listenref);
03357     #endif
03358         
03359     if (kOTNoError != err) {
03360         OSStatus status;
03361         status = OTCloseProvider (listenref->ep);   
03362         OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError);
03363         neterror ("install notifier for listen stream", err);
03364         goto exit;
03365         }
03366 
03367     err = OTSetAsynchronous (listenref->ep);
03368     
03369     if (kOTNoError != err) {
03370         OSStatus status;
03371         status = OTCloseProvider (listenref->ep);   
03372         OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError);
03373         neterror ("set listen stream to async mode", err);
03374         goto exit;
03375         }
03376     
03377     /* Push the listener on the global list of listeners, so we can close it on shutdown */
03378     
03379     OTAddFirst (&sListenList, &listenref->validationlink);
03380 
03381     /* Launch the worker thread that manages incoming connections */
03382     
03383     if (!fwslaunchacceptingthread (listenref)) { /* takes care of closing ep and cleaning up, even if we fail further down */
03384         OSStatus status;
03385         status = OTCloseProvider (listenref->ep);   
03386         OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError);
03387         goto exit;
03388         }
03389 
03390     /* Create configuration to be cloned for accepters */
03391     
03392     listenref->masterconfig = OTCreateConfiguration ("tcp");
03393 
03394     if (kOTInvalidConfigurationPtr == listenref->masterconfig || kOTNoMemoryConfigurationPtr == listenref->masterconfig) {
03395         memoryerror ();
03396         goto exit;
03397         }
03398     
03399     /* Allocate and clear memory for block of acceptors */
03400     
03401     listenref->acceptors = (EndpointRecordRef) NewPtr (depth * sizeof (tyendpointrecord));
03402 
03403     if (listenref->acceptors == nil) {
03404         memoryerror ();
03405         goto exit;
03406         }
03407     
03408     listenref->stats.cttotal = depth;
03409     
03410     OTMemzero (listenref->acceptors, depth * sizeof (tyendpointrecord));
03411 
03412     /* Loop over acceptors and open them asynchronously one by one */
03413     for (epref = listenref->acceptors, i = 0; i < depth; epref++, i++) {
03414         
03415         epref->listener = listenref;
03416     
03417         err = EPOpen (epref, OTCloneConfiguration (listenref->masterconfig));
03418         
03419         if (kOTNoError != err) {
03420             neterror ("create worker streams for listen stream", err);  
03421             goto exit;
03422             }
03423 
03424         listenref->stats.ctworking++;
03425         }
03426 
03427     /* Signal to the worker thread that we are ready to go */
03428 
03429     listenref->typeID = SOCKTYPE_LISTENING;
03430 
03431     /* Return to caller */
03432 
03433     *stream = (long) listenref;
03434 
03435     TCPTRACKEROUT ("fwsNetEventListenStream", __LINE__, nil, listenref);
03436 
03437     return (true);
03438 
03439 exit:
03440 
03441     //disposehandle (hcallbacktree);
03442         
03443     //neterror ("set up listen stream", err);
03444 
03445     return (false);
03446     } /*fwsNetEventListenStream*/
03447 
03448 
03449 boolean fwsNetEventCloseListen (unsigned long stream) {
03450 
03451     /*
03452     Close a listen and delete associated data
03453     
03454     7.0b35 PBS: pass gListSearchUPP to OTFindAndRemoveLink.
03455     */
03456 
03457     ListenRecordRef listenref = (ListenRecordRef) stream;
03458     OSStatus err;
03459     
03460     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03461         return (false);
03462     
03463     TCPTRACKERIN ("fwsNetEventCloseListen", __LINE__, nil, listenref);
03464 
03465     /* Find and remove from listener list */
03466     
03467     #if TARGET_API_MAC_CARBON == 1
03468         if (!OTFindAndRemoveLink (&sListenList, gListSearchUPP, (void *)listenref)) {
03469             intneterror (INTNETERROR_INVALIDSTREAM);
03470             return (false);
03471             }
03472     #else
03473         if (!OTFindAndRemoveLink (&sListenList, &listenlinkvisit, (void *)listenref)) {
03474             intneterror (INTNETERROR_INVALIDSTREAM);
03475             return (false);
03476             }
03477     #endif  
03478 
03479     /* Remove the notifier function */
03480 
03481     OTRemoveNotifier (listenref->ep);
03482     
03483     /* Set the listener to synchronous mode */
03484     
03485     err = OTSetSynchronous (listenref->ep);
03486     
03487     if (kOTNoError != err) {
03488         TCPERRORprintf (wsprintf (TCPmsg, "In fwscleanuplistener at line %d, error %ld setting listener %08lx to synchronous mode.", __LINE__, err, (long) listenref));
03489         TCPERRORWRITEMSG();
03490         }
03491     
03492     /* Close the listening endpoint itself */
03493     
03494     err = OTCloseProvider (listenref->ep);
03495     
03496     if (kOTNoError != err) {
03497         TCPERRORprintf (wsprintf (TCPmsg, "In fwscleanuplistener at line %d, error %ld closing listener %08lx.", __LINE__, err, (long) listenref));
03498         TCPERRORWRITEMSG();
03499         }
03500     
03501     /* Refer the actual clean up to the worker thread associated with the listener */
03502     
03503     listenref->typeID = SOCKTYPE_LISTENSTOPPED;
03504 
03505     TCPTRACKEROUT ("fwsNetEventCloseListen", __LINE__, nil, listenref);
03506 
03507     return (true);
03508     } /*fwsNetEventCloseListen*/
03509 
03510 
03511 void fwsNetEventShutdownDependentListeners (long hdatabase) {
03512 
03513     OTLink* listitem;
03514     ListenRecordRef listenref;
03515 
03516     #if TARGET_API_MAC_CARBON == 1
03517         OTListSearchUPP listendatabaseUPP = NewOTListSearchUPP(listendatabasevisit);
03518     #endif
03519     
03520     if (!frontierWinSockLoaded)
03521         return;
03522     
03523     
03524     while (true) {
03525         
03526         #if TARGET_API_MAC_CARBON == 1
03527             listitem = OTFindLink (&sListenList, listendatabaseUPP, (void *) hdatabase);
03528         #else
03529             listitem = OTFindLink (&sListenList, &listendatabasevisit, (void *) hdatabase);
03530         #endif
03531         
03532         if (listitem == nil)
03533             break;
03534     
03535         listenref = OTGetLinkObject (listitem, tylistenrecord, validationlink);
03536 
03537         OTRemoveLink (&sListenList, &listenref->validationlink);
03538         
03539         listenref->typeID = SOCKTYPE_LISTENSTOPPED; /* Leave clean up to worker thread */
03540         }
03541         
03542         #if TARGET_API_MAC_CARBON == 1
03543             DisposeOTListSearchUPP(listendatabaseUPP);
03544         #endif
03545     }/*fwsNetEventShutdownDependentListeners*/
03546 
03547 
03548 boolean fwsNetEventCheckAndAcceptSocket (void) {
03549     
03550     /*
03551     This is called from the main event loop.
03552     We don't have to do any accepting here,
03553     but use the opportunity to recycle broken EPs.
03554     */
03555     
03556     if (frontierWinSockLoaded)
03557 
03558         ProcessWaitingEndpoints (nil);
03559 
03560         Recycle (nil);
03561 
03562     return (true);
03563     }
03564 
03565 
03566 static short is_ipaddress (char *name) {
03567     
03568     short ctfields = 1;
03569     short fieldlen = 0;
03570     char *p = name;
03571     
03572     for (p = name; *p; ++p) {
03573         
03574         if (*p == '.') {
03575             
03576             if (fieldlen == 0) //leading dot, or consequtive dots
03577                 return (false);
03578             
03579             ++ctfields;
03580             
03581             fieldlen = 0;
03582             }
03583         else {
03584             if (!isdigit (*p))
03585                 return (false);
03586             
03587             if (++fieldlen > 3) // four consecutive digits
03588                 return (false);
03589             }
03590         }
03591     
03592     return (ctfields == 4);
03593     } /*is_ipaddress*/
03594 
03595 
03596 static boolean fwsOpenStream (TCall *ptrSndCall, unsigned long * stream) {
03597     
03598     /*
03599     Open a new endpoint asynchronously.
03600     */
03601     
03602     EndpointRecordRef epref;
03603     OTLink *epref_link = nil;
03604     OSStatus err;
03605 
03606     if (!incrementconnectioncounter ()) {
03607 
03608         plainneterror (BIGSTRING ("\x54" "Can't open stream because no more than five TCP connections may be open at any time."));
03609 
03610         return (false);
03611         }
03612 
03613     /* Try to obtain a new endpoint from the static list of idle endpoints */
03614     
03615     #if TARGET_API_MAC_CARBON != 1
03616         
03617         /*Always create new endpoints on OS X.*/
03618     
03619         epref_link = OTLIFODequeue (&sIdleEPs);
03620         
03621     #endif
03622     
03623     if (nil == epref_link) { /* No endpoints available, need to allocate and open a new one */
03624     
03625         epref = (EndpointRecordRef) NewPtr (sizeof (tyendpointrecord));
03626         
03627         if (nil == epref) {
03628             neterror ("open stream", memFullErr);
03629             decrementconnectioncounter();
03630             return (false);
03631             }
03632 
03633         InitEndpoint (epref, nil, nil);
03634         
03635         epref->sendCall = ptrSndCall;
03636         
03637         OTAtomicSetBit (&epref->stateflags, kWaitingForConnectBit);
03638 
03639         OTAtomicSetBit (&epref->stateflags, kDontDisposeBit);
03640 
03641         err = EPOpen (epref, OTCloneConfiguration (sMasterConfig));
03642         
03643         if (kOTNoError != err) {
03644             DisposePtr ((Ptr) epref);
03645             neterror ("open stream", err);
03646             decrementconnectioncounter();
03647             return (false);
03648             }
03649 
03650         epstats.cttotal++;
03651         
03652         epstats.ctworking++;
03653         }
03654     else {
03655     
03656         epstats.ctidle--;
03657         
03658         epstats.ctworking++;
03659         
03660         epref = OTGetLinkObject (epref_link, tyendpointrecord, link);
03661         
03662         InitEndpoint (epref, epref->ep, nil);
03663 
03664         epref->sendCall = ptrSndCall;
03665 
03666         OTAtomicSetBit (&epref->stateflags, kWaitingForConnectBit);
03667 
03668         OTAtomicSetBit (&epref->stateflags, kDontDisposeBit);
03669 
03670         err = EnterBind (epref);
03671 
03672         if (kOTNoError != err) {
03673             neterror ("open stream", err);
03674             CheckUnbind (epref, err, kQueueIt);
03675             decrementconnectioncounter();   
03676             return (false);
03677             }
03678         }
03679     
03680     /* Loop until open, bind, and connect have completed */
03681     
03682     while (!OTAtomicTestBit (&epref->completionflags, kConnectCompleteBit))
03683         if (!fwsbackgroundtask ()) {
03684             if (OTAtomicTestBit (&epref->stateflags, kBoundBit))
03685                 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
03686             else
03687                 CheckUnbind (epref, userCanceledErr, kQueueIt); 
03688             decrementconnectioncounter(); 
03689             return (false);
03690             }
03691     
03692     err = epref->result;
03693     
03694     if (kOTNoError != err) {
03695         neterror ("open stream", err);
03696         if (OTAtomicTestBit (&epref->stateflags, kBoundBit))
03697             CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
03698         else
03699             CheckUnbind (epref, err, kQueueIt); 
03700         decrementconnectioncounter();   
03701         return (false);
03702         }
03703     
03704     /* Clean up and return */
03705     
03706     epref->typeID = SOCKTYPE_OPEN;
03707     
03708     OTAddFirst (&sEndpointList, &epref->validationlink);
03709     
03710     *stream = (long) epref;
03711     
03712     return (true);
03713     }/*fwsOpenStream*/
03714 
03715 
03716 boolean fwsNetEventOpenAddrStream (unsigned long addr, unsigned long port, unsigned long * stream) {
03717 
03718     /*
03719     6.2b6 AR: Open Transport version
03720     */
03721     
03722     TCall sndCall;
03723     InetAddress hostAddress;
03724     
03725     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03726         return (false);
03727 
03728     TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventOpenAddrStream at line %d.  Address: %ld.", __LINE__, addr));
03729     TCPWRITEMSG();
03730     
03731     OTInitInetAddress (&hostAddress, port, addr);
03732 
03733     sndCall.addr.buf    = (UInt8 *) &hostAddress;
03734     sndCall.addr.len    = sizeof (hostAddress);
03735     sndCall.opt.buf     = nil;      // no connection options
03736     sndCall.opt.len     = 0;
03737     sndCall.udata.buf   = nil;      // no connection data
03738     sndCall.udata.len   = 0;
03739     sndCall.sequence    = 0;        // ignored by OTConnect
03740     
03741     return (fwsOpenStream (&sndCall, stream));
03742     } /*fwsNetEventOpenAddrStream*/
03743 
03744 
03745 boolean fwsNetEventOpenNameStream (bigstring name, unsigned long port, unsigned long * stream) {
03746 
03747     /*
03748     6.2b6 AR: Open Transport version.
03749     
03750     7.0b53 PBS: lower-case the domain name in the OS X version, else an error may be reported.
03751     */
03752 
03753     char sysstring[256];
03754     unsigned long addr;
03755     TCall sndCall;
03756     DNSAddress dnsaddress;
03757     
03758     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03759         return (false);
03760     
03761     #if TARGET_API_MAC_CARBON == 1
03762     
03763         alllower (name); /*7.0b44 PBS: OS X may return an error otherwise.*/
03764         
03765     #endif
03766 
03767     copyptocstring (name, sysstring);
03768         
03769     TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventOpenNameStream at line %d.  Domain name: %s.", __LINE__, sysstring));
03770     TCPWRITEMSG();
03771     
03772     if (is_ipaddress (sysstring)) {
03773         
03774         if (!fwsNetEventAddressEncode (name, &addr))
03775             return  (false);
03776         
03777         return (fwsNetEventOpenAddrStream (addr, port, stream));
03778         }
03779     
03780     #if TARGET_API_MAC_CARBON == 1 /*7.0b53 PBS: check the domain name*/
03781     
03782         if (!fwsNetEventNameToAddress (name, &addr))
03783             return (false);
03784     
03785     #endif
03786     
03787     wsprintf (sysstring, "%s:%ld", sysstring, port);
03788 
03789     sndCall.addr.len    = OTInitDNSAddress (&dnsaddress, sysstring);
03790     sndCall.addr.buf    = (UInt8 *) &dnsaddress;
03791     sndCall.opt.buf     = nil;      // no connection options
03792     sndCall.opt.len     = 0;
03793     sndCall.udata.buf   = nil;      // no connection data
03794     sndCall.udata.len   = 0;
03795     sndCall.sequence    = 0;        // ignored by OTConnect
03796         
03797     return (fwsOpenStream (&sndCall, stream));
03798     } /*fwsNetEventOpenNameStream*/
03799 
03800 
03801 boolean fwsNetEventAbortStream (unsigned long stream) {
03802 
03803     /*
03804     Abort a stream and delete associated data
03805 
03806     We trust the notifier and EnterSndDisconnect
03807     to do the right thing regarding clean-up.
03808     */
03809     
03810     EndpointRecordRef epref = (EndpointRecordRef) stream;
03811     OSStatus err;
03812 
03813     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03814         return (false);
03815 
03816     TCPTRACKERIN ("fwsNetEventAbortStream", __LINE__, epref, nil);
03817 
03818     /* Validate endpoint reference */
03819     
03820     if (!CheckEndpointList (epref)) {
03821         intneterror (INTNETERROR_INVALIDSTREAM);
03822         return (false);
03823         }
03824     
03825     /* Remove from list of valid endpoint references */
03826     
03827     OTRemoveLink (&sEndpointList, &epref->validationlink);
03828             
03829     /* Initiate abortive disconnect */
03830     
03831     err = EnterSndDisconnect (epref);
03832     
03833     if (kOTNoError != err) { // Scripts don't have to care about this error, it has already been taken care off anyway
03834         TCPERRORprintf (wsprintf (TCPmsg, "In fwsNetEventAbortStream at line %d, error %ld disconnecting endpoint %08lx.", __LINE__, err, (long) epref));
03835         TCPERRORWRITEMSG();
03836         }
03837 
03838     decrementconnectioncounter();
03839 
03840     TCPTRACKEROUT ("fwsNetEventAbortStream", __LINE__, epref, nil);
03841 
03842     return (true);
03843     } /*fwsNetEventAbortStream*/
03844 
03845 
03846 boolean fwsNetEventCloseStream (unsigned long stream) {
03847 
03848     /*
03849     Close a stream and delete associated data
03850     
03851     We trust the notifier and EnterSndOrderlyDisconnect
03852     to do the right thing regarding clean-up.
03853     */
03854 
03855     EndpointRecordRef epref = (EndpointRecordRef) stream;
03856     boolean doLeave;
03857 
03858     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03859         return (false);
03860 
03861     /* Validate endpoint reference */
03862     
03863     if (!CheckEndpointList (epref)) {
03864         intneterror (INTNETERROR_INVALIDSTREAM);
03865         return (false);
03866         }
03867     
03868     TCPTRACKEROUT ("fwsNetEventCloseStream", __LINE__, epref, nil);
03869     
03870     /* Remove from list of valid endpoint references */
03871     
03872     OTRemoveLink (&sEndpointList, &epref->validationlink);
03873     
03874     /* Initiate graceful disconnect */
03875     
03876     doLeave = OTEnterNotifier (epref->ep);
03877     
03878 
03879     /*bundle*/ {
03880         ListenRecordRef listenref = epref->listener;
03881         
03882         DoSndOrderlyDisconnect (epref, true);
03883                 
03884         if (0 == OTAtomicTestBit (&epref->stateflags, kBrokenBit)) {
03885 
03886             if (T_IDLE == OTGetEndpointState (epref->ep)) {
03887                 
03888                 OTAtomicClearBit (&epref->stateflags, kDontDisposeBit); /*pass on responsibility to the Notifier*/
03889                 
03890                 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt);
03891                 }
03892             else {
03893                     
03894                 epref->timestamp = timenow ();
03895                 
03896                 OTAtomicSetBit (&epref->stateflags, kWaitingForDisconnectBit);
03897 
03898                 if (listenref != nil) {
03899                     listenref->stats.ctworking--;
03900                     listenref->stats.ctwaiting++;
03901                     OTLIFOEnqueue (&listenref->waitingEPs, &epref->link); /*try again later*/
03902                     }
03903                 else {
03904                     epstats.ctworking--;
03905                     epstats.ctwaiting++;
03906                     OTLIFOEnqueue (&sWaitingEPs, &epref->link); /*try again later*/
03907                     }
03908                 }
03909             }
03910         }
03911     
03912     if (doLeave)
03913         OTLeaveNotifier (epref->ep);
03914 
03915     decrementconnectioncounter();
03916 
03917     TCPTRACKEROUT ("fwsNetEventCloseStream", __LINE__, epref, nil);
03918 
03919     return (true);
03920     } /*fwsNetEventCloseStream*/
03921     
03922     
03923 boolean fwsNetEventReadStream (unsigned long stream, unsigned long * bytesToRead, char * buffer) {
03924 
03925     /* Read from a stream */
03926 
03927     OTResult result = kOTNoError;
03928     OTFlags junkFlags;
03929     EndpointRecordRef epref = (EndpointRecordRef) stream;
03930     long ix = 0;
03931     long readcount = *bytesToRead;
03932     boolean doLeave = false;
03933     
03934     *bytesToRead = 0;
03935 
03936     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03937         return (false);
03938 
03939     TCPTRACKERIN ("fwsNetEventReadStream", __LINE__, epref, nil);
03940 
03941     if (!CheckEndpointList (epref)) {
03942         intneterror (INTNETERROR_INVALIDSTREAM);
03943         return (false);
03944         }
03945 
03946     doLeave = OTEnterNotifier (epref->ep);
03947 
03948     if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) {
03949         closedunexpectedlyerror ("read stream");
03950         goto error;
03951         }
03952 
03953     while (readcount > 0) {
03954 
03955         result = OTRcv (epref->ep, (void *) (buffer + ix), readcount, &junkFlags);
03956     
03957         if (result < 0) {
03958             
03959             if (kOTNoDataErr == result) { /* No data available for reading */
03960                 if (!fwsbackgroundtask ()) {
03961                     if (doLeave)
03962                         OTLeaveNotifier (epref->ep);
03963                     return (false);
03964                     }
03965                 continue;
03966                 }
03967 
03968             if (kOTLookErr == result) {
03969                 
03970                 OTResult eventcode = OTLook (epref->ep);
03971                 
03972                 switch (eventcode) {
03973                     
03974                     case T_DISCONNECT: {    /* Receive and break out */
03975                         EnterRcvDisconnect (epref);
03976                         closedunexpectedlyerror ("read stream");
03977                         goto error;
03978                         }
03979                     
03980                     case T_ORDREL: {    /* Receive and try again */
03981                         EnterRcvOrderlyDisconnect (epref);
03982                         closedunexpectedlyerror ("read stream");
03983                         goto error;
03984                         }
03985                     
03986                     case T_GODATA: { /* Try again */
03987                         TCP_MSG_2 ("OTLook after OTRcv returned T_GODATA");
03988                         continue;
03989                         }
03990                     
03991                     default: {
03992                         neterror ("write stream", result);
03993                         goto error;
03994                         }
03995                     }
03996                 }
03997             else {
03998                 neterror("read stream", result);
03999                 goto error;
04000                 }
04001             }
04002         
04003         readcount -= result;
04004         
04005         ix += result;
04006 
04007         *bytesToRead = ix;
04008         }/*while*/
04009 
04010     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStream at line %d.  Bytes requested = %ld, read = %ld.", __LINE__, *bytesToRead, (unsigned long) result));
04011     TCPWRITEMSG ();
04012 
04013     if (doLeave)
04014         OTLeaveNotifier (epref->ep);
04015 
04016     return (true);
04017 
04018 error:
04019 
04020     if (doLeave)
04021         OTLeaveNotifier (epref->ep);
04022 
04023     return (false);
04024     } /*fwsNetEventReadStream*/
04025 
04026 
04027 boolean fwsNetEventWriteStream (unsigned long stream, unsigned long bytesToWrite, char * buffer) {
04028 
04029     /*
04030     Write to a Stream
04031     
04032     5.0.2b3 dmb: if we write fewer bytes than requested, we need to retry, generate error
04033     
04034     6.2b9 AR: The above change doesn't really work since scripts have no way to find out
04035     which part of the data needs to be resend. Instead of throwing an error, keep trying.
04036     */
04037     
04038     EndpointRecordRef epref = (EndpointRecordRef) stream;
04039     OTResult result = kOTNoError;
04040     long ix = 0;
04041     boolean doLeave = false;
04042 
04043     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04044         return (false);
04045 
04046     TCPTRACKERIN ("fwsNetEventWriteStream", __LINE__, epref, nil);
04047 
04048     if (!CheckEndpointList (epref)) {
04049         intneterror (INTNETERROR_INVALIDSTREAM);
04050         return (false);
04051         }
04052     
04053     doLeave = OTEnterNotifier (epref->ep);
04054     
04055     if (OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) {
04056         closedunexpectedlyerror ("write stream");
04057         goto exit;
04058         }
04059     
04060     while (bytesToWrite > 0) {
04061 
04062         result = OTSnd (epref->ep, (void *) (buffer + ix), bytesToWrite, nil);
04063     
04064         if (result <= 0) {
04065             
04066             if (kOTFlowErr == result) {
04067                 if (!fwsbackgroundtask ()) {
04068                     if (doLeave)
04069                         OTLeaveNotifier (epref->ep);
04070                     return (false);
04071                     }
04072                 continue;
04073                 }
04074 
04075             if (kOTLookErr == result) {
04076                 
04077                 OTResult eventcode = OTLook (epref->ep);
04078                 
04079                 switch (eventcode) {
04080                     
04081                     case T_DISCONNECT: {    /* Receive and break out */
04082                         EnterRcvDisconnect (epref);
04083                         closedunexpectedlyerror ("write stream");
04084                         goto exit;
04085                         }
04086                     
04087                     case T_ORDREL: {    /* Receive and try again */
04088                         EnterRcvOrderlyDisconnect (epref);
04089                         continue;
04090                         }
04091                     
04092                     case T_GODATA: { /* Try again */
04093                         TCP_MSG_2 ("OTLook after OTSnd returned T_GODATA");
04094                         continue;
04095                         }
04096                     
04097                     default: {
04098                         neterror ("write stream", result);
04099                         goto exit;
04100                         }
04101                     }
04102                 }
04103             else {
04104                 neterror("write stream", result);
04105                 goto exit;
04106                 }
04107             }
04108 
04109         TCPprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d, requested writing %ld bytes, wrote %ld bytes.", __LINE__, bytesToWrite, result));
04110         TCPWRITEMSG ();
04111 
04112         bytesToWrite -= result;
04113         
04114         ix += result;
04115         }
04116 
04117     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteStream at line %d.  Bytes requested = %ld, written = %ld.", __LINE__, bytesToWrite, (unsigned long) result));
04118     TCPWRITEMSG ();
04119     
04120     if (doLeave)
04121         OTLeaveNotifier (epref->ep);
04122         
04123     return (true);
04124 
04125 exit:
04126 
04127     if (doLeave)
04128         OTLeaveNotifier (epref->ep);
04129         
04130     return (false);
04131     } /*fwsNetEventWriteStream*/
04132 
04133 
04134 
04135 boolean fwsNetEventStatusStream (unsigned long stream, bigstring status, unsigned long * bytesPending) {
04136 
04137     /* get the status of a stream */
04138 
04139     EndpointRecordRef epref = (EndpointRecordRef) stream;
04140     ListenRecordRef listenref = (ListenRecordRef) stream;
04141     tysocktypeid typeID = SOCKTYPE_INVALID;
04142 
04143     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04144         return (false);
04145         
04146     *bytesPending = 0;
04147 
04148     if (CheckEndpointList (epref)) {
04149         typeID = epref->typeID;
04150         if (!inmainthread())
04151             TCPTRACKERIN ("fwsNetEventStatusStream", __LINE__, epref, nil);
04152         }
04153 
04154     if (CheckListenList (listenref)) {
04155         typeID = listenref->typeID;
04156         if (!inmainthread())
04157             TCPTRACKERIN ("fwsNetEventStatusStream", __LINE__, nil, listenref);
04158         }
04159     
04160     if (!epref && !listenref && !inmainthread ()) {
04161         TCPTRACKERIN ("fwsNetEventStatusStream", __LINE__, epref, listenref);
04162         }
04163 
04164     switch (typeID) {
04165         case SOCKTYPE_INVALID:
04166             intneterror(INTNETERROR_INVALIDSTREAM);
04167             copyctopstring ("INACTIVE", status);
04168             return (false);
04169 
04170         case SOCKTYPE_UNKNOWN:
04171             copyctopstring ("UNKNOWN", status);
04172             break;
04173 
04174         case SOCKTYPE_OPEN: {
04175             OTResult result;
04176         
04177             copyctopstring ("OPEN", status);
04178         
04179             result = OTCountDataBytes (epref->ep, (OTByteCount*) bytesPending);
04180             
04181             switch (result) {
04182                 
04183                 case kOTNoError: {
04184                     if (*bytesPending != 0)
04185                         copyctopstring ("DATA", status);
04186                     else
04187                         copyctopstring ("OPEN", status);
04188                     break;
04189                     }
04190         
04191                 case kOTNoDataErr: {
04192                     copyctopstring ("OPEN", status);
04193                     break;
04194                     }
04195                 
04196                 case kOTLookErr: {
04197                     
04198                     OTResult eventcode = OTLook (epref->ep);
04199                     
04200                     switch (eventcode) {
04201                         
04202                         case T_DISCONNECT: {    /* Receive and break out */
04203                             //EnterRcvDisconnect (epref); /* Don't actually disconnect here, leave that up to fwsNetEventCloseStream */
04204                             copyctopstring ("INACTIVE", status);
04205                             epref->typeID = SOCKTYPE_INACTIVE;
04206                             break;
04207                             }
04208                         
04209                         case T_ORDREL: {    /* Receive and try again */
04210                             EnterRcvOrderlyDisconnect (epref); /* Don't actually disconnect here, leave that up to fwsNetEventCloseStream */
04211                             copyctopstring ("INACTIVE", status);
04212                             epref->typeID = SOCKTYPE_INACTIVE;
04213                             break;
04214                             }
04215                         
04216                         default: {
04217                             copyctopstring ("OPEN", status);
04218                             break;
04219                             }
04220                         }
04221                     break;
04222                     }
04223                 
04224                 case kOTOutStateErr:
04225                     if (*bytesPending == 0)
04226                         break;
04227                         
04228                 default:
04229                     neterror("check status on stream", result);
04230                     copyctopstring ("INACTIVE", status);
04231                     epref->typeID = SOCKTYPE_INACTIVE;
04232                     return (false);
04233                 }
04234                 
04235             if (*bytesPending == 0)
04236                 if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) {
04237                     copyctopstring ("INACTIVE", status);
04238                     epref->typeID = SOCKTYPE_INACTIVE;
04239                     }
04240 
04241             break;
04242             }
04243 
04244         case SOCKTYPE_LISTENING:
04245             copyctopstring ("LISTENING", status);
04246             break;
04247 
04248         case SOCKTYPE_CLOSED:
04249             copyctopstring ("CLOSED", status);
04250             break;
04251 
04252         case SOCKTYPE_LISTENSTOPPED:
04253             copyctopstring ("STOPPED", status);
04254             break;
04255 
04256         case SOCKTYPE_INACTIVE:
04257             copyctopstring ("INACTIVE", status);
04258             break;
04259 
04260         default:
04261             copyctopstring ("UNKNOWN", status);
04262             break;
04263         }
04264 
04265     nullterminate (status);
04266 
04267     if (!inmainthread()) {
04268         TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventStatusStream at line %d, result is %s with bytes pending %ld.", __LINE__, stringbaseaddress(status), *bytesPending));
04269         TCPWRITEMSG ();
04270         }
04271 
04272     return (true);
04273     } /*fwsNetEventStatusStream*/
04274 
04275 
04276 boolean fwsNetEventGetPeerAddress (unsigned long stream, unsigned long * peeraddress, unsigned long * peerport) {
04277 
04278     EndpointRecordRef epref = (EndpointRecordRef) stream;
04279     TBind* peerAddr;
04280     OSStatus err;
04281 
04282     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04283         return (false);
04284 
04285     TCPTRACKERIN ("fwsNetEventGetPeerAddress", __LINE__, epref, nil);
04286 
04287     if (!CheckEndpointList (epref)) {
04288         intneterror (INTNETERROR_INVALIDSTREAM);
04289         return (false);
04290         }
04291     //Code change by Timothy Paustian Monday, June 26, 2000 4:07:42 PM
04292     //
04293     #if TARGET_API_MAC_CARBON == 1
04294         peerAddr = OTAllocInContext (epref->ep, T_BIND, T_ADDR, &err, nil); 
04295     #else
04296         peerAddr = OTAlloc (epref->ep, T_BIND, T_ADDR, &err);
04297     #endif
04298         
04299     if (err != kOTNoError) {
04300         neterror ("get peer address", err);
04301         return (false);
04302         }
04303         
04304     OTAtomicClearBit (&epref->completionflags, kGetProtAddressBit);
04305     
04306     err = OTGetProtAddress (epref->ep, nil, peerAddr);
04307 
04308     if (err != kOTNoError) {
04309         neterror ("get peer address", err);
04310         OTFree (peerAddr, T_BIND);
04311         return (false);
04312         }
04313     
04314     while (!OTAtomicTestBit (&epref->completionflags, kGetProtAddressBit))
04315         YieldToAnyThread ();
04316     
04317     //OTAssert ("fwsNetEventGetPeerAddress: size of peer address structure doesn't match InetAddress", sizeof (InetAddress) == peerAddr->addr.len);
04318 
04319     //OTAssert ("fwsNetEventGetPeerAddress: size of peer address structure doesn't match InetAddress", AF_INET == ((InetAddress*) peerAddr->addr.buf)->fAddressType);
04320         
04321     *peerport = ((InetAddress*) peerAddr->addr.buf)->fPort;
04322     
04323     *peeraddress = ((InetAddress*) peerAddr->addr.buf)->fHost;  
04324 
04325     OTFree (peerAddr, T_BIND);
04326 
04327     TCPTRACKEROUT ("fwsNetEventGetPeerAddress", __LINE__, epref, nil);
04328 
04329     return (true);
04330     } /*fwsNetEventGetPeerAddress*/
04331 
04332 
04333 boolean fwsNetEventReadStreamUntil (unsigned long stream, Handle hbuffer, Handle hpattern, unsigned long timeoutsecs) {
04334 
04335     /*
04336     Read data from stream. Don't return until we found the pattern or until we timed out.
04337     */
04338 
04339     EndpointRecordRef epref = (EndpointRecordRef) stream;
04340     long ix = gethandlesize (hbuffer);
04341     long ixstart = ix;
04342     OTFlags junkFlags;
04343     OTResult result;
04344     long timeoutticks;
04345     boolean doLeave = false;
04346 
04347     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04348         return (false);
04349 
04350     TCPTRACKERIN ("fwsNetEventReadStreamUntil", __LINE__, epref, nil);
04351 
04352     if (searchhandle (hbuffer, hpattern, 0, ix) != -1L)
04353         return (true);
04354 
04355     if (!CheckEndpointList (epref)) {
04356         intneterror (INTNETERROR_INVALIDSTREAM);
04357         return (false);
04358         }
04359     
04360     doLeave = OTEnterNotifier (epref->ep);
04361         
04362     if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit))
04363         goto error_closedprematurely;
04364 
04365     if (!sethandlesize (hbuffer, ix + kPacketSize)) {
04366         if (doLeave)
04367             OTLeaveNotifier (epref->ep);
04368         return (false);
04369         }
04370     
04371     timeoutticks = gettickcount () + (timeoutsecs * 60);
04372 
04373     while (true) {
04374 
04375         lockhandle (hbuffer);
04376 
04377         result = OTRcv (epref->ep, &((*hbuffer) [ix]), kPacketSize, &junkFlags);
04378 
04379         unlockhandle (hbuffer);
04380 
04381         if (result < 0) {
04382 
04383             if (kOTNoDataErr == result) {
04384                 
04385                 if (gettickcount () > timeoutticks) {
04386                     result = kETIMEDOUTErr;
04387                     goto exit;
04388                     }
04389                 
04390                 if (!fwsbackgroundtask ()) {
04391                     if (doLeave)
04392                         OTLeaveNotifier (epref->ep);
04393                     return (false);
04394                     }
04395                 
04396                 continue;
04397                 }
04398             
04399             if (kOTLookErr == result) {
04400             
04401                 result = OTLook (epref->ep);
04402                 
04403                 switch (result) {
04404                     
04405                     case T_ORDREL:
04406                         EnterRcvOrderlyDisconnect (epref);
04407                         goto error_closedprematurely;
04408                     
04409                     case T_DISCONNECT:
04410                         EnterRcvDisconnect (epref);
04411                         goto error_closedprematurely;
04412                     
04413                     case T_GODATA:
04414                         TCP_MSG_2 ("OTLook after OTRcv returned T_GODATA");
04415                         continue; /*ignore it*/
04416                     
04417                     default:
04418                         result = kOTLookErr;
04419                         goto exit;
04420                     }
04421                 }
04422             else
04423                 goto exit;
04424             }
04425 
04426         TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntil at line %d, read %ld bytes.", __LINE__, result));
04427         TCPWRITEMSG ();
04428 
04429         ix += result;
04430         
04431         if (searchhandle (hbuffer, hpattern, 0, ix) != -1L)
04432             break;
04433         
04434         if (!sethandlesize (hbuffer, ix + kPacketSize)) { /* Make room for another 8k */
04435             if (doLeave)
04436                 OTLeaveNotifier (epref->ep);
04437             return (false);
04438             }
04439     
04440         timeoutticks = gettickcount () + (timeoutsecs * 60);
04441         }/*while*/
04442 
04443     if (!sethandlesize (hbuffer, ix)) {
04444         if (doLeave)
04445             OTLeaveNotifier (epref->ep);
04446         return (false);
04447         }
04448 
04449     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamUntil at line %d.  Total bytes read = %ld.", __LINE__, ix - ixstart));
04450     TCPWRITEMSG ();
04451 
04452     if (doLeave)
04453         OTLeaveNotifier (epref->ep);
04454 
04455     return (true);
04456 
04457 exit:
04458 
04459     sethandlesize (hbuffer, ix);
04460 
04461     neterror ("read stream", result);
04462     
04463     if (doLeave)
04464         OTLeaveNotifier (epref->ep);
04465         
04466     return (false);
04467 
04468 error_closedprematurely:
04469 
04470     sethandlesize (hbuffer, ix);
04471 
04472     closedunexpectedlyerror ("read stream");
04473 
04474     if (doLeave)
04475         OTLeaveNotifier (epref->ep);
04476 
04477     return (false);
04478     } /*fwsNetEventReadStreamUntil*/
04479 
04480 
04481 
04482 boolean fwsNetEventReadStreamUntilClosed (unsigned long stream, Handle hbuffer, unsigned long timeoutsecs) {
04483 
04484     /*
04485     Read data from stream until closed.
04486     */
04487 
04488     EndpointRecordRef epref = (EndpointRecordRef) stream;
04489     long ix = gethandlesize (hbuffer);
04490     long ixstart = ix;
04491     OTFlags junkFlags;
04492     OTResult result;
04493     long timeoutticks;
04494     boolean doLeave = false;
04495 
04496     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04497         return (false);
04498 
04499     TCPTRACKERIN ("fwsNetEventReadStreamUntilClosed", __LINE__, epref, nil);
04500 
04501     if (!CheckEndpointList (epref)) {
04502         intneterror (INTNETERROR_INVALIDSTREAM);
04503         return (false);
04504         }
04505     
04506     doLeave = OTEnterNotifier (epref->ep);
04507     
04508     if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit))
04509         goto done; /* 08/08/2000 AR: we're done already */
04510     
04511     if (!sethandlesize (hbuffer, ix + kPacketSize)) {
04512         if (doLeave)
04513             OTLeaveNotifier (epref->ep);
04514         return (false);
04515         }
04516 
04517     timeoutticks = gettickcount () + (timeoutsecs * 60);
04518 
04519     while (true) {
04520         
04521         lockhandle (hbuffer);
04522 
04523         result = OTRcv (epref->ep, &((*hbuffer) [ix]), kPacketSize, &junkFlags);
04524 
04525         unlockhandle (hbuffer);
04526 
04527         if (result < 0) {
04528         
04529             if (kOTNoDataErr == result) {
04530                 
04531                 if (gettickcount () > timeoutticks) {
04532                     neterror ("read stream", kETIMEDOUTErr);
04533                     goto exit;
04534                     }
04535 
04536                 if (!fwsbackgroundtask ()) {
04537                     if (doLeave)
04538                         OTLeaveNotifier (epref->ep);
04539                     return (false);
04540                     }
04541                 
04542                 continue;
04543                 }
04544             
04545             if (kOTLookErr == result) {
04546             
04547                 result = OTLook (epref->ep);
04548                 
04549                 switch (result) {
04550                     
04551                     case T_ORDREL:
04552                         EnterRcvOrderlyDisconnect (epref);
04553                         goto done;
04554                     
04555                     case T_DISCONNECT:
04556                         EnterRcvDisconnect (epref);
04557                         goto done;
04558                     
04559                     case T_GODATA:
04560                         TCP_MSG_2 ("OTLook after OTRcv returned T_GODATA");
04561                         continue; /*ignore it*/
04562                     
04563                     default:
04564                         neterror ("read stream", kOTLookErr);
04565                         goto exit;
04566                     }
04567                 }
04568             else {
04569                 neterror ("read stream", result);
04570                 goto exit;
04571                 }
04572             }
04573 
04574         TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntilClosed at line %d, read %ld bytes.", __LINE__, result));
04575         TCPWRITEMSG ();
04576 
04577         ix += result;
04578 
04579         if (!sethandlesize (hbuffer, ix + kPacketSize))
04580             return (false); /*we have the thread globals, so we can return immediately*/
04581 
04582         timeoutticks = gettickcount () + (timeoutsecs * 60);
04583         }/*while*/
04584 
04585 done:
04586 
04587     if (!sethandlesize (hbuffer, ix))
04588         return (false);
04589 
04590     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamUntilClosed at line %d.  Total bytes read = %ld.", __LINE__, ix - ixstart));
04591     TCPWRITEMSG ();
04592     
04593     if (doLeave)
04594         OTLeaveNotifier (epref->ep);
04595 
04596     return (true);
04597 
04598 exit:
04599 
04600     if (!sethandlesize (hbuffer, ix))
04601         return (false);
04602     
04603     if (doLeave)
04604         OTLeaveNotifier (epref->ep);
04605 
04606     return (false);
04607     }/*fwsNetEventReadStreamUntilClosed*/
04608 
04609 
04610 boolean fwsNetEventReadStreamBytes (unsigned long stream, Handle hbuffer, long ctbytes, unsigned long timeoutsecs) {
04611 
04612     /*
04613     Read the specified number of bytes from the stream appending to hbuffer.
04614     */
04615 
04616     EndpointRecordRef epref = (EndpointRecordRef) stream;
04617     long lenbuffer = gethandlesize (hbuffer);
04618     long ix = lenbuffer;
04619     OTResult result;
04620     OTFlags junkFlags;
04621     long timeoutticks;
04622     boolean doLeave = false;
04623 
04624     if (ix >= ctbytes) /*6.1b8 AR: don't do anything*/
04625         return (true);
04626 
04627     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04628         return (false);
04629 
04630     TCPTRACKERIN ("fwsNetEventReadStreamBytes", __LINE__, epref, nil);
04631 
04632     if (!CheckEndpointList (epref)) {
04633         intneterror (INTNETERROR_INVALIDSTREAM);
04634         return (false);
04635         }
04636 
04637     doLeave = OTEnterNotifier (epref->ep);
04638 
04639     if (!sethandlesize (hbuffer, ctbytes)) { //make enough room in one go
04640         if (doLeave)
04641             OTLeaveNotifier (epref->ep);
04642         return (false);
04643         }
04644 
04645     lockhandle (hbuffer);
04646     
04647     if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit))
04648         goto error_closedprematurely;
04649         
04650     timeoutticks = gettickcount () + (timeoutsecs * 60);
04651 
04652     while (ix < ctbytes) {
04653 
04654         result = OTRcv (epref->ep, (void *) &((*hbuffer)[ix]), ctbytes - ix, &junkFlags);
04655         
04656         if (result < 0) {
04657         
04658             if (kOTNoDataErr == result) {
04659                 
04660                 if (gettickcount () > timeoutticks) {
04661                     result = kETIMEDOUTErr;
04662                     goto exit;
04663                     }
04664 
04665                 if (!fwsbackgroundtask ()) {
04666                     unlockhandle (hbuffer);
04667                     if (doLeave)
04668                         OTLeaveNotifier (epref->ep);
04669                     return (false);
04670                     }
04671                 
04672                 continue;
04673                 }
04674             
04675             if (kOTLookErr == result) {
04676             
04677                 result = OTLook (epref->ep);
04678                 
04679                 switch (result) {
04680                     
04681                     case T_ORDREL:
04682                         EnterRcvOrderlyDisconnect (epref);
04683                         goto error_closedprematurely;
04684                     
04685                     case T_DISCONNECT:
04686                         EnterRcvDisconnect (epref);
04687                         goto error_closedprematurely;
04688                     
04689                     case T_GODATA:
04690                         TCP_MSG_2 ("OTLook after OTRcv returned T_GODATA");
04691                         continue; /*ignore it*/
04692                     
04693                     default:
04694                         result = kOTLookErr;
04695                         goto exit;
04696                     }
04697                 }
04698             else
04699                 goto exit;
04700             }
04701 
04702         TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamBytes at line %d, read %ld bytes.", __LINE__, result));
04703         TCPWRITEMSG ();
04704 
04705         ix += result;
04706 
04707         timeoutticks = gettickcount () + (timeoutsecs * 60);
04708         }/*while*/
04709 
04710     unlockhandle (hbuffer);
04711 
04712     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamBytes at line %d.  Total bytes requested = %ld, bytes read = %ld.", __LINE__, ctbytes, ix));
04713     TCPWRITEMSG ();
04714 
04715     if (doLeave)
04716         OTLeaveNotifier (epref->ep);
04717     
04718     return (true);
04719 
04720 exit:
04721 
04722     unlockhandle (hbuffer);
04723 
04724     sethandlesize (hbuffer, ix); /*shrinking, can't fail*/
04725 
04726     neterror ("read stream", result);
04727 
04728     if (doLeave)
04729         OTLeaveNotifier (epref->ep);
04730 
04731     return (false);
04732 
04733 error_closedprematurely:
04734 
04735     closedunexpectedlyerror ("read stream");
04736 
04737     unlockhandle (hbuffer);
04738 
04739     sethandlesize (hbuffer, ix); /*shrinking, can't fail*/
04740 
04741     if (doLeave)
04742         OTLeaveNotifier (epref->ep);
04743         
04744     return (false);
04745     } /*fwsNetEventReadStreamBytes*/
04746 
04747 
04748 boolean fwsNetEventWriteHandleToStream (unsigned long stream, Handle hbuffer, unsigned long chunksize, unsigned long timeoutsecs) {
04749 
04750     /* Write to stream in chunks */
04751 
04752     EndpointRecordRef epref = (EndpointRecordRef) stream;
04753     unsigned long bytesremaining = gethandlesize (hbuffer);
04754     long ix = 0;
04755     long bytestowrite;
04756     OTResult result;
04757     long timeoutticks;
04758     boolean doLeave = false;
04759 
04760     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04761         return (false);
04762 
04763     TCPTRACKERIN ("fwsNetEventWriteHandleToStream", __LINE__, epref, nil);
04764 
04765     if (!CheckEndpointList (epref)) {
04766         intneterror (INTNETERROR_INVALIDSTREAM);
04767         return (false);
04768         }
04769     
04770     doLeave = OTEnterNotifier (epref->ep);
04771 
04772     lockhandle (hbuffer);
04773     
04774     if (OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit))
04775         goto error_closedprematurely;
04776 
04777     timeoutticks = gettickcount () + (timeoutsecs * 60);
04778 
04779     do {
04780     
04781         bytestowrite = (bytesremaining < chunksize) ? bytesremaining : chunksize;
04782     
04783         result = OTSnd (epref->ep, &((*hbuffer) [ix]), bytestowrite, nil);
04784     
04785         if (result <= 0) {
04786         
04787             if (kOTFlowErr == result) {
04788                 
04789                 if (gettickcount () > timeoutticks) {
04790                     result = kETIMEDOUTErr;
04791                     goto exit;
04792                     }
04793 
04794                 if (!fwsbackgroundtask ()) {
04795                     unlockhandle (hbuffer);
04796                     if (doLeave)
04797                         OTLeaveNotifier (epref->ep);
04798                     return (false);
04799                     }
04800                 
04801                 continue;
04802                 }
04803             
04804             if (kOTLookErr == result) {
04805             
04806                 result = OTLook (epref->ep);
04807                 
04808                 switch (result) {
04809                     
04810                     case T_ORDREL:
04811                         EnterRcvOrderlyDisconnect (epref);
04812                         goto error_closedprematurely;
04813                     
04814                     case T_DISCONNECT:
04815                         EnterRcvDisconnect (epref);
04816                         goto error_closedprematurely;
04817                     
04818                     case T_GODATA:
04819                         continue; /*ignore it*/
04820                     
04821                     default:
04822                         result = kOTLookErr;
04823                         goto exit;
04824                     }
04825                 }
04826             else
04827                 goto exit;
04828             }
04829 
04830         TCPprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d, requested writing %ld bytes, wrote %ld bytes.", __LINE__, bytestowrite, result));
04831         TCPWRITEMSG ();
04832 
04833         bytesremaining -= result;
04834         
04835         ix += result;
04836 
04837         timeoutticks = gettickcount () + (timeoutsecs * 60);
04838 
04839     } while (bytesremaining > 0);
04840     
04841     unlockhandle (hbuffer);
04842 
04843     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteHandleToStream at line %d.  Total bytes written = %ld.", __LINE__, ix));
04844     TCPWRITEMSG ();
04845     
04846     if (doLeave)
04847         OTLeaveNotifier (epref->ep);
04848         
04849     return (true);
04850 
04851 exit:
04852 
04853     unlockhandle (hbuffer);
04854 
04855     neterror("write stream", result);
04856     
04857     if (doLeave)
04858         OTLeaveNotifier (epref->ep);
04859 
04860     return (false);
04861 
04862 error_closedprematurely:
04863 
04864     unlockhandle (hbuffer);
04865 
04866     closedunexpectedlyerror ("write stream");
04867     
04868     if (doLeave)
04869         OTLeaveNotifier (epref->ep);
04870 
04871     return (false);
04872     } /*fwsNetEventWriteHandleToStream*/
04873 
04874 
04875 static boolean fwstransmitfile (unsigned long stream, ptrfilespec fs) {
04876 
04877     char *buffer;
04878     static const long kFileBufferSize = 32767L;
04879     boolean fl = false;
04880     hdlfilenum fnum;
04881     long ctread = 0;
04882     long ix = 0;
04883 
04884     /* open file */
04885 
04886     if (!openfile (fs, &fnum, true))
04887         return (false);
04888 
04889     /* allocate buffer */
04890 
04891     buffer = malloc (kFileBufferSize);
04892 
04893     if (buffer == nil) {
04894         memoryerror ();
04895         goto exit;
04896         }
04897         
04898     while (true) {
04899 
04900         /* read from file */
04901         
04902         if (!filesetposition (fnum, ix))
04903             goto exit;
04904 
04905         if (!filereaddata (fnum, kFileBufferSize, &ctread, buffer))
04906             goto exit;
04907 
04908         if (ctread == 0) {
04909             fl = true;
04910             goto exit;
04911             }
04912         
04913         ix += ctread;
04914 
04915         /* write to stream */
04916 
04917         if(!fwsNetEventWriteStream (stream, ctread, buffer))
04918             goto exit;
04919         }
04920 
04921 exit:
04922     /* free buffer */
04923 
04924     if (buffer != nil)
04925         free (buffer);
04926 
04927     /* close file */
04928 
04929     fl = closefile (fnum);
04930 
04931     return (fl);
04932     }/*fwstransmitfile*/
04933 
04934 
04935 boolean fwsNetEventWriteFileToStream (unsigned long stream, Handle hprefix, Handle hsuffix, ptrfilespec fs) {
04936 
04937     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04938         return (false);
04939 
04940     TCPTRACKERIN ("fwsNetEventWriteFileToStream", __LINE__, (EndpointRecordRef) stream, nil);
04941 
04942     if (hprefix != nil) {
04943         boolean fl;
04944 
04945         lockhandle (hprefix);
04946 
04947         fl = fwsNetEventWriteStream (stream, gethandlesize (hprefix), *hprefix);
04948 
04949         unlockhandle (hprefix);
04950 
04951         if (!fl)
04952             return (false);
04953         }
04954 
04955     if (!fwstransmitfile (stream, fs))
04956         return (false);
04957 
04958     if (hsuffix != nil) {
04959         boolean fl;
04960 
04961         lockhandle (hsuffix);
04962 
04963         fl = fwsNetEventWriteStream (stream, gethandlesize (hsuffix), *hsuffix);
04964 
04965         unlockhandle (hsuffix);
04966 
04967         if (!fl)
04968             return (false);
04969         }
04970 
04971     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteFileToStream at line %d.\n", __LINE__));
04972     TCPWRITEMSG ();
04973 
04974     return (true); 
04975     } /*fwsNetEventWriteFileToStream*/
04976 
04977 //#endif
04978 
04979 
04980 boolean fwsNetEventInetdRead (unsigned long stream, Handle hbuffer, unsigned long timeoutsecs) {
04981 
04982     /*
04983     6.1b2 AR: Wait timeoutsecs seconds for data to come in. After the first packet has been
04984     received, continue reading with a reduced timeout of .5 second. (For historical reasons.)
04985     */
04986 
04987     EndpointRecordRef epref = (EndpointRecordRef) stream;
04988     OTResult result;
04989     OTFlags junkFlags;
04990     long ix = gethandlesize (hbuffer);
04991     long ixstart = ix;
04992     long timeoutticks;
04993     boolean doLeave = false;
04994 
04995     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04996         return (false);
04997 
04998     TCPTRACKERIN ("fwsNetEventInetdRead", __LINE__, epref, nil);
04999 
05000     if (!CheckEndpointList (epref)) {
05001         intneterror (INTNETERROR_INVALIDSTREAM);
05002         return (false);
05003         }
05004 
05005     doLeave = OTEnterNotifier (epref->ep);
05006     
05007     if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit))
05008         goto done;
05009 
05010     timeoutticks = gettickcount () + (timeoutsecs * 60);
05011 
05012     while (true) {
05013         
05014         lockhandle (hbuffer);
05015 
05016         result = OTRcv (epref->ep, &((*hbuffer) [ix]), kPacketSize, &junkFlags);
05017 
05018         unlockhandle (hbuffer);
05019 
05020         if (result < 0) {
05021         
05022             if (kOTNoDataErr == result) {
05023                 
05024                 if (gettickcount () > timeoutticks)
05025                     goto done; /* simply stop reading, don't throw an error */
05026 
05027                 YieldToAnyThread ();
05028                 
05029                 continue;
05030                 }
05031             
05032             if (kOTLookErr == result) {
05033             
05034                 result = OTLook (epref->ep);
05035                 
05036                 switch (result) {
05037                     
05038                     case T_ORDREL:
05039                         EnterRcvOrderlyDisconnect (epref);
05040                         goto done;
05041                     
05042                     case T_DISCONNECT:
05043                         EnterRcvDisconnect (epref);
05044                         goto done;
05045                     
05046                     case T_GODATA:
05047                         TCP_MSG_2("OTLook after OTRcv returned T_GODATA");
05048                         continue; /*ignore it*/
05049                     
05050                     default:
05051                         result = kOTLookErr;
05052                         goto exit;
05053                     }
05054                 }
05055             else
05056                 goto exit;
05057             }
05058 
05059         TCPprintf (wsprintf(TCPmsg, "In fwsNetEventInetdRead at line %d, requested reading %ld bytes, read %ld bytes.", __LINE__, kPacketSize, result));
05060         TCPWRITEMSG ();
05061 
05062         ix += result;
05063 
05064         if (!sethandlesize (hbuffer, ix + kPacketSize)) {
05065             if (doLeave)
05066                 OTLeaveNotifier (epref->ep);
05067             return (false);
05068             }
05069 
05070         timeoutticks = gettickcount () + 30;
05071         }/*while*/
05072 
05073 done:
05074     if (!sethandlesize (hbuffer, ix))
05075         return (false);
05076 
05077     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventInetdRead at line %d.  Total bytes read = %ld.", __LINE__, ix - ixstart));
05078     TCPWRITEMSG ();
05079 
05080     if (doLeave)
05081         OTLeaveNotifier (epref->ep);
05082         
05083     return (true);
05084 
05085 exit:
05086     neterror ("read stream", result);
05087 
05088     if (doLeave)
05089         OTLeaveNotifier (epref->ep);
05090 
05091     return (false);
05092     } /*fwsNetEventInetdRead*/
05093 
05094 
05095 boolean fwsNetEventGetStats (unsigned long stream, bigstring bs) {
05096     
05097     setemptystring (bs);
05098     
05099     if (nil != stream) {
05100         
05101         ListenRecordRef listenref = (ListenRecordRef) stream;
05102     
05103         if (!CheckListenList (listenref)) {
05104             intneterror (INTNETERROR_INVALIDSTREAM);
05105             return (false);
05106             }
05107 
05108         pushlong (listenref->stats.cttotal, bs);
05109     
05110         pushchar (',', bs);
05111     
05112         pushlong (listenref->stats.ctidle, bs);
05113     
05114         pushchar (',', bs);
05115     
05116         pushlong (listenref->stats.ctworking, bs);
05117     
05118         pushchar (',', bs);
05119     
05120         pushlong (listenref->stats.ctwaiting, bs);
05121     
05122         pushchar (',', bs);
05123     
05124         pushlong (listenref->stats.ctbroken, bs);
05125         }
05126     else {
05127     
05128         pushlong (epstats.cttotal, bs);
05129     
05130         pushchar (',', bs);
05131     
05132         pushlong (epstats.ctidle, bs);
05133     
05134         pushchar (',', bs);
05135     
05136         pushlong (epstats.ctbroken, bs);
05137     
05138         pushchar (',', bs);
05139     
05140         pushlong (epstats.ctworking, bs);
05141         }
05142 
05143     return (true);
05144     }/*fwsNetEventGetStats*/
05145 

Generated on Wed May 31 18:19:56 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6